~ubuntu-branches/ubuntu/saucy/quagga/saucy

« back to all changes in this revision

Viewing changes to isisd/isis_pfpacket.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephan Hermann
  • Date: 2007-09-14 09:47:54 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070914094754-kqi815lcg6n8mh51
Tags: 0.99.9-1ubuntu1
* Merged new upstream version (LP: #139376)
  - Merged debian/changelog
* Fixes a DoS and some bugs introduced in 0.99.8
  (see: http://www.quagga.net/news2.php?y=2007&m=9&d=7#id1189190760)
* Remaining Ubuntu Patches:
  - debian/rules: use bash as shell
  - debian/quagga.prerm: handle upgrades more gracefully
  - debian/patches/81_32bit_u64.dpatch: Define __u64 as uint64_t
    before including the netlink headers, since that symbol does not exist
    by default on 32 bit arches. Fixes i386/powerpc FTBFS.
  - debian/patches/83_ifaddr_defs.dpatch:
    zebra/rt_netlink.c: #include <linux/if_addr.h> and define IF[L]A_RTA
    macros, so that the file compiles again with our kernel headers.
  - debian/patches/20_ht-20061217-0.99.6-bgp-md5.dpatch: updated for
    linux kernel 2.6.20.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * IS-IS Rout(e)ing protocol - isis_pfpacket.c
 
3
 *
 
4
 * Copyright (C) 2001,2002    Sampo Saaristo
 
5
 *                            Tampere University of Technology      
 
6
 *                            Institute of Communications Engineering
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify it 
 
9
 * under the terms of the GNU General Public Licenseas published by the Free 
 
10
 * Software Foundation; either version 2 of the License, or (at your option) 
 
11
 * any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,but WITHOUT 
 
14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 
15
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
 
16
 * more details.
 
17
 
 
18
 * You should have received a copy of the GNU General Public License along 
 
19
 * with this program; if not, write to the Free Software Foundation, Inc., 
 
20
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
21
 */
 
22
 
 
23
#include <zebra.h>
 
24
#include <net/ethernet.h>       /* the L2 protocols */
 
25
#include <netpacket/packet.h>
 
26
 
 
27
#include "log.h"
 
28
#include "stream.h"
 
29
#include "if.h"
 
30
 
 
31
#include "isisd/dict.h"
 
32
#include "isisd/include-netbsd/iso.h"
 
33
#include "isisd/isis_constants.h"
 
34
#include "isisd/isis_common.h"
 
35
#include "isisd/isis_circuit.h"
 
36
#include "isisd/isis_flags.h"
 
37
#include "isisd/isisd.h"
 
38
#include "isisd/isis_constants.h"
 
39
#include "isisd/isis_circuit.h"
 
40
#include "isisd/isis_network.h"
 
41
 
 
42
#include "privs.h"
 
43
 
 
44
extern struct zebra_privs_t isisd_privs;
 
45
 
 
46
/*
 
47
 * Table 9 - Architectural constants for use with ISO 8802 subnetworks
 
48
 * ISO 10589 - 8.4.8
 
49
 */
 
50
 
 
51
u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 };
 
52
u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 };
 
53
u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 };
 
54
u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 };
 
55
 
 
56
static char discard_buff[8192];
 
57
static char sock_buff[8192];
 
58
 
 
59
/*
 
60
 * if level is 0 we are joining p2p multicast
 
61
 * FIXME: and the p2p multicast being ???
 
62
 */
 
63
static int
 
64
isis_multicast_join (int fd, int registerto, int if_num)
 
65
{
 
66
  struct packet_mreq mreq;
 
67
 
 
68
  memset (&mreq, 0, sizeof (mreq));
 
69
  mreq.mr_ifindex = if_num;
 
70
  if (registerto)
 
71
    {
 
72
      mreq.mr_type = PACKET_MR_MULTICAST;
 
73
      mreq.mr_alen = ETH_ALEN;
 
74
      if (registerto == 1)
 
75
        memcpy (&mreq.mr_address, ALL_L1_ISS, ETH_ALEN);
 
76
      else if (registerto == 2)
 
77
        memcpy (&mreq.mr_address, ALL_L2_ISS, ETH_ALEN);
 
78
      else if (registerto == 3)
 
79
        memcpy (&mreq.mr_address, ALL_ISS, ETH_ALEN);
 
80
      else
 
81
        memcpy (&mreq.mr_address, ALL_ESS, ETH_ALEN);
 
82
 
 
83
    }
 
84
  else
 
85
    {
 
86
      mreq.mr_type = PACKET_MR_ALLMULTI;
 
87
    }
 
88
#ifdef EXTREME_DEBUG
 
89
  zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, "
 
90
              "address = %02x:%02x:%02x:%02x:%02x:%02x",
 
91
              fd, registerto, if_num, mreq.mr_address[0], mreq.mr_address[1],
 
92
              mreq.mr_address[2], mreq.mr_address[3], mreq.mr_address[4],
 
93
              mreq.mr_address[5]);
 
94
#endif /* EXTREME_DEBUG */
 
95
  if (setsockopt (fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
 
96
                  sizeof (struct packet_mreq)))
 
97
    {
 
98
      zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno));
 
99
      return ISIS_WARNING;
 
100
    }
 
101
 
 
102
  return ISIS_OK;
 
103
}
 
104
 
 
105
static int
 
106
open_packet_socket (struct isis_circuit *circuit)
 
107
{
 
108
  struct sockaddr_ll s_addr;
 
109
  int fd, retval = ISIS_OK;
 
110
 
 
111
  fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL));
 
112
  if (fd < 0)
 
113
    {
 
114
      zlog_warn ("open_packet_socket(): socket() failed %s",
 
115
                 safe_strerror (errno));
 
116
      return ISIS_WARNING;
 
117
    }
 
118
 
 
119
  /*
 
120
   * Bind to the physical interface
 
121
   */
 
122
  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
 
123
  s_addr.sll_family = AF_PACKET;
 
124
  s_addr.sll_protocol = htons (ETH_P_ALL);
 
125
  s_addr.sll_ifindex = circuit->interface->ifindex;
 
126
 
 
127
  if (bind (fd, (struct sockaddr *) (&s_addr),
 
128
            sizeof (struct sockaddr_ll)) < 0)
 
129
    {
 
130
      zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno));
 
131
      return ISIS_WARNING;
 
132
    }
 
133
 
 
134
  circuit->fd = fd;
 
135
 
 
136
  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 
137
    {
 
138
      /*
 
139
       * Join to multicast groups
 
140
       * according to
 
141
       * 8.4.2 - Broadcast subnetwork IIH PDUs
 
142
       * FIXME: is there a case only one will fail??
 
143
       */
 
144
      if (circuit->circuit_is_type & IS_LEVEL_1)
 
145
        {
 
146
          /* joining ALL_L1_ISS */
 
147
          retval = isis_multicast_join (circuit->fd, 1,
 
148
                                        circuit->interface->ifindex);
 
149
          /* joining ALL_ISS */
 
150
          retval = isis_multicast_join (circuit->fd, 3,
 
151
                                        circuit->interface->ifindex);
 
152
        }
 
153
      if (circuit->circuit_is_type & IS_LEVEL_2)
 
154
        /* joining ALL_L2_ISS */
 
155
        retval = isis_multicast_join (circuit->fd, 2,
 
156
                                      circuit->interface->ifindex);
 
157
    }
 
158
  else
 
159
    {
 
160
      retval =
 
161
        isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
 
162
    }
 
163
 
 
164
  return retval;
 
165
}
 
166
 
 
167
/*
 
168
 * Create the socket and set the tx/rx funcs
 
169
 */
 
170
int
 
171
isis_sock_init (struct isis_circuit *circuit)
 
172
{
 
173
  int retval = ISIS_OK;
 
174
 
 
175
  if (isisd_privs.change (ZPRIVS_RAISE))
 
176
    zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno));
 
177
 
 
178
  retval = open_packet_socket (circuit);
 
179
 
 
180
  if (retval != ISIS_OK)
 
181
    {
 
182
      zlog_warn ("%s: could not initialize the socket", __func__);
 
183
      goto end;
 
184
    }
 
185
 
 
186
  if (circuit->circ_type == CIRCUIT_T_BROADCAST)
 
187
    {
 
188
      circuit->tx = isis_send_pdu_bcast;
 
189
      circuit->rx = isis_recv_pdu_bcast;
 
190
    }
 
191
  else if (circuit->circ_type == CIRCUIT_T_P2P)
 
192
    {
 
193
      circuit->tx = isis_send_pdu_p2p;
 
194
      circuit->rx = isis_recv_pdu_p2p;
 
195
    }
 
196
  else
 
197
    {
 
198
      zlog_warn ("isis_sock_init(): unknown circuit type");
 
199
      retval = ISIS_WARNING;
 
200
      goto end;
 
201
    }
 
202
 
 
203
end:
 
204
  if (isisd_privs.change (ZPRIVS_LOWER))
 
205
    zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno));
 
206
 
 
207
  return retval;
 
208
}
 
209
 
 
210
static inline int
 
211
llc_check (u_char * llc)
 
212
{
 
213
  if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3)
 
214
    return 0;
 
215
 
 
216
  return 1;
 
217
}
 
218
 
 
219
int
 
220
isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)
 
221
{
 
222
  int bytesread, addr_len;
 
223
  struct sockaddr_ll s_addr;
 
224
  u_char llc[LLC_LEN];
 
225
 
 
226
  addr_len = sizeof (s_addr);
 
227
 
 
228
  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
 
229
 
 
230
  bytesread = recvfrom (circuit->fd, (void *) &llc,
 
231
                        LLC_LEN, MSG_PEEK,
 
232
                        (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
 
233
 
 
234
  if (bytesread < 0)
 
235
    {
 
236
      zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
 
237
                 circuit->fd, safe_strerror (errno));
 
238
      zlog_warn ("circuit is %s", circuit->interface->name);
 
239
      zlog_warn ("circuit fd %d", circuit->fd);
 
240
      zlog_warn ("bytesread %d", bytesread);
 
241
      /* get rid of the packet */
 
242
      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
 
243
      return ISIS_WARNING;
 
244
    }
 
245
  /*
 
246
   * Filtering by llc field, discard packets sent by this host (other circuit)
 
247
   */
 
248
  if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
 
249
    {
 
250
      /*  Read the packet into discard buff */
 
251
      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
 
252
      if (bytesread < 0)
 
253
        zlog_warn ("isis_recv_pdu_bcast(): read() failed");
 
254
      return ISIS_WARNING;
 
255
    }
 
256
 
 
257
  /* on lan we have to read to the static buff first */
 
258
  bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0,
 
259
                        (struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
 
260
 
 
261
  /* then we lose the LLC */
 
262
  stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
 
263
 
 
264
  memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
 
265
 
 
266
  return ISIS_OK;
 
267
}
 
268
 
 
269
int
 
270
isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)
 
271
{
 
272
  int bytesread, addr_len;
 
273
  struct sockaddr_ll s_addr;
 
274
 
 
275
  memset (&s_addr, 0, sizeof (struct sockaddr_ll));
 
276
  addr_len = sizeof (s_addr);
 
277
 
 
278
  /* we can read directly to the stream */
 
279
  bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd,
 
280
                               circuit->interface->mtu, 0,
 
281
                               (struct sockaddr *) &s_addr, 
 
282
                               (socklen_t *) &addr_len);
 
283
 
 
284
  if (s_addr.sll_pkttype == PACKET_OUTGOING)
 
285
    {
 
286
      /*  Read the packet into discard buff */
 
287
      bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
 
288
      if (bytesread < 0)
 
289
        zlog_warn ("isis_recv_pdu_p2p(): read() failed");
 
290
      return ISIS_WARNING;
 
291
    }
 
292
 
 
293
  /* If we don't have protocol type 0x00FE which is
 
294
   * ISO over GRE we exit with pain :)
 
295
   */
 
296
  if (ntohs (s_addr.sll_protocol) != 0x00FE)
 
297
    {
 
298
      zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X",
 
299
                 ntohs (s_addr.sll_protocol));
 
300
      return ISIS_WARNING;
 
301
    }
 
302
 
 
303
  memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen);
 
304
 
 
305
  return ISIS_OK;
 
306
}
 
307
 
 
308
int
 
309
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
 
310
{
 
311
  /* we need to do the LLC in here because of P2P circuits, which will
 
312
   * not need it
 
313
   */
 
314
  int written = 1;
 
315
  struct sockaddr_ll sa;
 
316
 
 
317
  stream_set_getp (circuit->snd_stream, 0);
 
318
  memset (&sa, 0, sizeof (struct sockaddr_ll));
 
319
  sa.sll_family = AF_PACKET;
 
320
  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
 
321
  sa.sll_ifindex = circuit->interface->ifindex;
 
322
  sa.sll_halen = ETH_ALEN;
 
323
  if (level == 1)
 
324
    memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
 
325
  else
 
326
    memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
 
327
 
 
328
  /* on a broadcast circuit */
 
329
  /* first we put the LLC in */
 
330
  sock_buff[0] = 0xFE;
 
331
  sock_buff[1] = 0xFE;
 
332
  sock_buff[2] = 0x03;
 
333
 
 
334
  /* then we copy the data */
 
335
  memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
 
336
          stream_get_endp (circuit->snd_stream));
 
337
 
 
338
  /* now we can send this */
 
339
  written = sendto (circuit->fd, sock_buff,
 
340
                    stream_get_endp(circuit->snd_stream) + LLC_LEN, 0,
 
341
                    (struct sockaddr *) &sa, sizeof (struct sockaddr_ll));
 
342
 
 
343
  return ISIS_OK;
 
344
}
 
345
 
 
346
int
 
347
isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
 
348
{
 
349
 
 
350
  int written = 1;
 
351
  struct sockaddr_ll sa;
 
352
 
 
353
  stream_set_getp (circuit->snd_stream, 0);
 
354
  memset (&sa, 0, sizeof (struct sockaddr_ll));
 
355
  sa.sll_family = AF_PACKET;
 
356
  sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
 
357
  sa.sll_ifindex = circuit->interface->ifindex;
 
358
  sa.sll_halen = ETH_ALEN;
 
359
  if (level == 1)
 
360
    memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
 
361
  else
 
362
    memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
 
363
 
 
364
 
 
365
  /* lets try correcting the protocol */
 
366
  sa.sll_protocol = htons (0x00FE);
 
367
  written = sendto (circuit->fd, circuit->snd_stream->data,
 
368
                    stream_get_endp (circuit->snd_stream), 0, 
 
369
                    (struct sockaddr *) &sa,
 
370
                    sizeof (struct sockaddr_ll));
 
371
 
 
372
  return ISIS_OK;
 
373
}