~ubuntu-branches/debian/sid/ircd-hybrid/sid

« back to all changes in this revision

Viewing changes to src/packet.c

  • Committer: Package Import Robot
  • Author(s): Dominic Hargreaves
  • Date: 2015-04-19 15:53:09 UTC
  • mfrom: (1.2.13)
  • Revision ID: package-import@ubuntu.com-20150419155309-06y59x2at2ax5ou3
Tags: 1:8.2.7+dfsg.1-1
* Remove Suggests: hybserv since it doesn't really work with
  ircd-hybrid 8 and above
* New upstream release
  - update debian/copyright with minor changes
  - update config files from new reference.conf
  - fixes DoS from localhost clients (Closes: #782859)
  - supports SSL certficate chaining (Closes: #769741)
* Debconf configuration script no longer ignores the result of
  upgrade questions (Closes: #779082)
* Don't display upgrade warnings on new installs (Closes: #782883)
* Add NEWS item about updated configuration

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3
3
 *
4
 
 *  Copyright (c) 1997-2014 ircd-hybrid development team
 
4
 *  Copyright (c) 1997-2015 ircd-hybrid development team
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
21
21
 
22
22
/*! \file packet.c
23
23
 * \brief Packet handlers.
24
 
 * \version $Id: packet.c 4564 2014-08-24 10:24:47Z michael $
 
24
 * \version $Id: packet.c 5546 2015-02-12 14:13:48Z michael $
25
25
 */
26
26
 
27
27
#include "stdinc.h"
42
42
#define READBUF_SIZE 16384
43
43
 
44
44
static char readBuf[READBUF_SIZE];
45
 
static void client_dopacket(struct Client *, char *, size_t);
 
45
 
 
46
 
 
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
 *      It is implicitly assumed that client_dopacket() is called only
 
56
 *      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, unsigned int 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
}
46
72
 
47
73
/* extract_one_line()
48
74
 *
51
77
 * output       - length of <buffer>
52
78
 * side effects - one line is copied and removed from the dbuf
53
79
 */
54
 
static int
 
80
static unsigned int
55
81
extract_one_line(struct dbuf_queue *qptr, char *buffer)
56
82
{
57
 
  int line_bytes = 0, empty_bytes = 0, phase = 0;
58
 
  unsigned int idx = 0;
59
 
  dlink_node *ptr = NULL;
 
83
  unsigned int line_bytes = 0, eol_bytes = 0;
 
84
  dlink_node *node;
60
85
 
61
 
  /*
62
 
   * Phase 0: "empty" characters before the line
63
 
   * Phase 1: copying the line
64
 
   * Phase 2: "empty" characters after the line
65
 
   *          (delete them as well and free some space in the dbuf)
66
 
   *
67
 
   * Empty characters are CR, LF and space (but, of course, not
68
 
   * in the middle of a line). We try to remove as much of them as we can,
69
 
   * since they simply eat server memory.
70
 
   *
71
 
   * --adx
72
 
   */
73
 
  DLINK_FOREACH(ptr, qptr->blocks.head)
 
86
  DLINK_FOREACH(node, qptr->blocks.head)
74
87
  {
75
 
    struct dbuf_block *block = ptr->data;
 
88
    const struct dbuf_block *block = node->data;
 
89
    unsigned int idx;
76
90
 
77
 
    if (ptr == qptr->blocks.head)
 
91
    if (node == qptr->blocks.head)
78
92
      idx = qptr->pos;
79
93
    else
80
94
      idx = 0;
83
97
    {
84
98
      char c = block->data[idx];
85
99
 
86
 
      if (IsEol(c) || (c == ' ' && phase != 1))
 
100
      if (IsEol(c))
87
101
      {
88
 
        ++empty_bytes;
 
102
        ++eol_bytes;
89
103
 
90
 
        if (phase == 1)
91
 
          phase = 2;
92
 
      }
93
 
      else switch (phase)
94
 
      {
95
 
        case 0: phase = 1;
96
 
        case 1: if (line_bytes++ < IRCD_BUFSIZE - 2)
97
 
                  *buffer++ = c;
98
 
                break;
99
 
        case 2: *buffer = '\0';
100
 
                dbuf_delete(qptr, line_bytes + empty_bytes);
101
 
                return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
102
 
      }
 
104
        /* Allow 2 eol bytes per message */
 
105
        if (eol_bytes == 2)
 
106
          goto out;
 
107
      }
 
108
      else if (eol_bytes)
 
109
        goto out;
 
110
      else if (line_bytes++ < IRCD_BUFSIZE - 2)
 
111
        *buffer++ = c;
103
112
    }
104
113
  }
105
114
 
 
115
out:
 
116
 
106
117
  /*
107
 
   * Now, if we haven't reached phase 2, ignore all line bytes
 
118
   * Now, if we haven't found an EOL, ignore all line bytes
108
119
   * that we have read, since this is a partial line case.
109
120
   */
110
 
  if (phase != 2)
 
121
  if (eol_bytes)
 
122
    *buffer = '\0';
 
123
  else
111
124
    line_bytes = 0;
112
 
  else
113
 
    *buffer = '\0';
114
125
 
115
126
  /* Remove what is now unnecessary */
116
 
  dbuf_delete(qptr, line_bytes + empty_bytes);
 
127
  dbuf_delete(qptr, line_bytes + eol_bytes);
 
128
 
117
129
  return IRCD_MIN(line_bytes, IRCD_BUFSIZE - 2);
118
130
}
 
131
 
119
132
/*
120
133
 * parse_client_queued - parse client queued messages
121
134
 */
122
135
static void
123
136
parse_client_queued(struct Client *client_p)
124
137
{
125
 
  int dolen = 0;
126
 
  int checkflood = 1;
127
 
  struct LocalUser *lclient_p = client_p->localClient;
 
138
  unsigned int dolen = 0;
128
139
 
129
140
  if (IsUnknown(client_p))
130
141
  {
131
 
    int i = 0;
 
142
    unsigned int i = 0;
132
143
 
133
144
    while (1)
134
145
    {
135
146
      if (IsDefunct(client_p))
136
147
        return;
137
148
 
138
 
      /* rate unknown clients at MAX_FLOOD per loop */
 
149
      /* Rate unknown clients at MAX_FLOOD per loop */
139
150
      if (i >= MAX_FLOOD)
140
151
        break;
141
152
 
142
 
      dolen = extract_one_line(&lclient_p->buf_recvq, readBuf);
 
153
      dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
 
154
 
143
155
      if (dolen == 0)
144
156
        break;
145
157
 
146
158
      client_dopacket(client_p, readBuf, dolen);
147
 
      i++;
 
159
      ++i;
148
160
 
149
 
      /* if they've dropped out of the unknown state, break and move
 
161
      /*
 
162
       * If they've dropped out of the unknown state, break and move
150
163
       * to the parsing for their appropriate status.  --fl
151
164
       */
152
165
      if (!IsUnknown(client_p))
160
173
    {
161
174
      if (IsDefunct(client_p))
162
175
        return;
163
 
      if ((dolen = extract_one_line(&lclient_p->buf_recvq, readBuf)) == 0)
 
176
 
 
177
      if ((dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf)) == 0)
164
178
        break;
165
179
 
166
180
      client_dopacket(client_p, readBuf, dolen);
168
182
  }
169
183
  else if (IsClient(client_p))
170
184
  {
171
 
    if (ConfigGeneral.no_oper_flood && (HasUMode(client_p, UMODE_OPER) || IsCanFlood(client_p)))
172
 
    {
173
 
      if (ConfigGeneral.true_no_oper_flood)
174
 
        checkflood = -1;
175
 
      else
176
 
        checkflood = 0;
177
 
    }
 
185
    unsigned int checkflood = 1;
 
186
 
 
187
    if (ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER))
 
188
      checkflood = 0;
 
189
    else if (IsCanFlood(client_p))
 
190
      checkflood = 0;
178
191
 
179
192
    /*
180
 
     * Handle flood protection here - if we exceed our flood limit on
181
 
     * messages in this loop, we simply drop out of the loop prematurely.
 
193
     * Handle flood protection here - if we exceed our flood limit on messages
 
194
     * in this loop, we simply drop out of the loop prematurely.
182
195
     *   -- adrian
183
196
     */
184
197
    while (1)
186
199
      if (IsDefunct(client_p))
187
200
        break;
188
201
 
189
 
      /* This flood protection works as follows:
 
202
      /*
 
203
       * This flood protection works as follows:
190
204
       *
191
205
       * A client is given allow_read lines to send to the server.  Every
192
206
       * time a line is parsed, sent_parsed is increased.  sent_parsed
199
213
       * as sent_parsed will always hover around the allow_read limit
200
214
       * and no 'bursts' will be permitted.
201
215
       */
202
 
      if (checkflood > 0)
203
 
      {
204
 
        if (lclient_p->sent_parsed >= lclient_p->allow_read)
 
216
      if (checkflood)
 
217
        if (client_p->connection->sent_parsed >= client_p->connection->allow_read)
205
218
          break;
206
 
      }
207
 
 
208
 
      /* allow opers 4 times the amount of messages as users. why 4?
209
 
       * why not. :) --fl_
210
 
       */
211
 
      else if (lclient_p->sent_parsed >= (4 * lclient_p->allow_read) && checkflood != -1)
212
 
        break;
213
 
 
214
 
      dolen = extract_one_line(&lclient_p->buf_recvq, readBuf);
 
219
 
 
220
      dolen = extract_one_line(&client_p->connection->buf_recvq, readBuf);
 
221
 
215
222
      if (dolen == 0)
216
223
        break;
217
224
 
218
225
      client_dopacket(client_p, readBuf, dolen);
219
 
      lclient_p->sent_parsed++;
 
226
      ++client_p->connection->sent_parsed;
220
227
    }
221
228
  }
222
229
}
231
238
  SetFloodDone(client_p);
232
239
 
233
240
  /* Drop their flood limit back down */
234
 
  client_p->localClient->allow_read = MAX_FLOOD;
 
241
  client_p->connection->allow_read = MAX_FLOOD;
235
242
 
236
 
  /* sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
 
243
  /*
 
244
   * sent_parsed could be way over MAX_FLOOD but under MAX_FLOOD_BURST,
237
245
   * so reset it.
238
246
   */
239
 
  client_p->localClient->sent_parsed = 0;
 
247
  client_p->connection->sent_parsed = 0;
240
248
}
241
249
 
242
250
/*
248
256
void
249
257
flood_recalc(fde_t *fd, void *data)
250
258
{
251
 
  struct Client *client_p = data;
252
 
  struct LocalUser *lclient_p = client_p->localClient;
 
259
  struct Client *const client_p = data;
253
260
 
254
 
  /* allow a bursting client their allocation per second, allow
 
261
  /*
 
262
   * Allow a bursting client their allocation per second, allow
255
263
   * a client whos flooding an extra 2 per second
256
264
   */
257
265
  if (IsFloodDone(client_p))
258
 
    lclient_p->sent_parsed -= 2;
 
266
    client_p->connection->sent_parsed -= 2;
259
267
  else
260
 
    lclient_p->sent_parsed = 0;
 
268
    client_p->connection->sent_parsed = 0;
261
269
 
262
 
  if (lclient_p->sent_parsed < 0)
263
 
    lclient_p->sent_parsed = 0;
 
270
  if (client_p->connection->sent_parsed < 0)
 
271
    client_p->connection->sent_parsed = 0;
264
272
 
265
273
  parse_client_queued(client_p);
266
274
 
278
286
void
279
287
read_packet(fde_t *fd, void *data)
280
288
{
281
 
  struct Client *client_p = data;
 
289
  struct Client *const client_p = data;
282
290
  int length = 0;
283
291
 
284
292
  if (IsDefunct(client_p))
323
331
    if (length <= 0)
324
332
    {
325
333
      /*
326
 
       * If true, then we can recover from this error.  Just jump out of
 
334
       * If true, then we can recover from this error. Just jump out of
327
335
       * the loop and re-register a new io-request.
328
336
       */
329
337
      if (length < 0 && ignoreErrno(errno))
333
341
      return;
334
342
    }
335
343
 
336
 
    dbuf_put(&client_p->localClient->buf_recvq, readBuf, length);
337
 
 
338
 
    if (client_p->localClient->lasttime < CurrentTime)
339
 
      client_p->localClient->lasttime = CurrentTime;
340
 
    if (client_p->localClient->lasttime > client_p->localClient->since)
341
 
      client_p->localClient->since = CurrentTime;
 
344
    dbuf_put(&client_p->connection->buf_recvq, readBuf, length);
 
345
 
 
346
    if (client_p->connection->lasttime < CurrentTime)
 
347
      client_p->connection->lasttime = CurrentTime;
 
348
 
 
349
    if (client_p->connection->lasttime > client_p->connection->since)
 
350
      client_p->connection->since = CurrentTime;
342
351
 
343
352
    ClearPingSent(client_p);
344
353
 
349
358
      return;
350
359
 
351
360
    /* Check to make sure we're not flooding */
352
 
    if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p))
353
 
        && (dbuf_length(&client_p->localClient->buf_recvq) >
354
 
            get_recvq(&client_p->localClient->confs)))
 
361
    if (!(IsServer(client_p) || IsHandshake(client_p) || IsConnecting(client_p)) &&
 
362
        (dbuf_length(&client_p->connection->buf_recvq) >
 
363
         get_recvq(&client_p->connection->confs)))
355
364
    {
356
 
      if (!(ConfigGeneral.no_oper_flood && HasUMode(client_p, UMODE_OPER)))
357
 
      {
358
 
        exit_client(client_p, "Excess Flood");
359
 
        return;
360
 
      }
 
365
      exit_client(client_p, "Excess Flood");
 
366
      return;
361
367
    }
362
368
  }
363
369
#ifdef HAVE_LIBCRYPTO
369
375
  /* If we get here, we need to register for another COMM_SELECT_READ */
370
376
  comm_setselect(fd, COMM_SELECT_READ, read_packet, client_p, 0);
371
377
}
372
 
 
373
 
/*
374
 
 * client_dopacket - copy packet to client buf and parse it
375
 
 *      client_p - pointer to client structure for which the buffer data
376
 
 *             applies.
377
 
 *      buffer - pointr to the buffer containing the newly read data
378
 
 *      length - number of valid bytes of data in the buffer
379
 
 *
380
 
 * Note:
381
 
 *      It is implicitly assumed that dopacket is called only
382
 
 *      with client_p of "local" variation, which contains all the
383
 
 *      necessary fields (buffer etc..)
384
 
 */
385
 
static void
386
 
client_dopacket(struct Client *client_p, char *buffer, size_t length)
387
 
{
388
 
  /*
389
 
   * Update messages received
390
 
   */
391
 
  ++me.localClient->recv.messages;
392
 
  ++client_p->localClient->recv.messages;
393
 
 
394
 
  /*
395
 
   * Update bytes received
396
 
   */
397
 
  client_p->localClient->recv.bytes += length;
398
 
  me.localClient->recv.bytes += length;
399
 
 
400
 
  parse(client_p, buffer, buffer + length);
401
 
}