Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / proto / radv / packets.c @ 6b3f1a54

History | View | Annotate | Download (10.6 KB)

1
/*
2
 *        BIRD -- RAdv Packet Processing
3
 *
4
 *
5
 *        Can be freely distributed and used under the terms of the GNU GPL.
6
 */
7

    
8

    
9
#include <stdlib.h>
10
#include "radv.h"
11

    
12
struct radv_ra_packet
13
{
14
  u8 type;
15
  u8 code;
16
  u16 checksum;
17
  u8 current_hop_limit;
18
  u8 flags;
19
  u16 router_lifetime;
20
  u32 reachable_time;
21
  u32 retrans_timer;
22
};
23

    
24
#define OPT_RA_MANAGED 0x80
25
#define OPT_RA_OTHER_CFG 0x40
26

    
27
#define OPT_PREFIX        3
28
#define OPT_MTU                5
29
#define OPT_ROUTE        24
30
#define OPT_RDNSS        25
31
#define OPT_DNSSL        31
32

    
33
struct radv_opt_prefix
34
{
35
  u8 type;
36
  u8 length;
37
  u8 pxlen;
38
  u8 flags;
39
  u32 valid_lifetime;
40
  u32 preferred_lifetime;
41
  u32 reserved;
42
  ip6_addr prefix;
43
};
44

    
45
#define OPT_PX_ONLINK 0x80
46
#define OPT_PX_AUTONOMOUS 0x40
47

    
48
struct radv_opt_mtu
49
{
50
  u8 type;
51
  u8 length;
52
  u16 reserved;
53
  u32 mtu;
54
};
55

    
56
struct radv_opt_route {
57
  u8 type;
58
  u8 length;
59
  u8 pxlen;
60
  u8 flags;
61
  u32 lifetime;
62
  u8 prefix[];
63
};
64

    
65
struct radv_opt_rdnss
66
{
67
  u8 type;
68
  u8 length;
69
  u16 reserved;
70
  u32 lifetime;
71
  ip6_addr servers[];
72
};
73

    
74
struct radv_opt_dnssl
75
{
76
  u8 type;
77
  u8 length;
78
  u16 reserved;
79
  u32 lifetime;
80
  char domain[];
81
};
82

    
83
static int
84
radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt,
85
                   char **buf, char *bufend)
86
{
87
  struct radv_proto *p = ifa->ra;
88
  u8 px_blocks = (net6_pxlen(rt->n.addr) + 63) / 64;
89
  u8 opt_len = 8 * (1 + px_blocks);
90

    
91
  if (*buf + opt_len > bufend)
92
  {
93
    log(L_WARN, "%s: Too many RA options on interface %s",
94
        p->p.name, ifa->iface->name);
95
    return -1;
96
  }
97

    
98
  uint preference = rt->preference_set ? rt->preference : ifa->cf->route_preference;
99
  uint lifetime = rt->lifetime_set ? rt->lifetime : ifa->cf->route_lifetime;
100
  uint valid = rt->valid && p->valid && (p->active || !ifa->cf->route_lifetime_sensitive);
101

    
102
  struct radv_opt_route *opt = (void *) *buf;
103
  *buf += opt_len;
104
  opt->type = OPT_ROUTE;
105
  opt->length = 1 + px_blocks;
106
  opt->pxlen = net6_pxlen(rt->n.addr);
107
  opt->flags = preference;
108
  opt->lifetime = valid ? htonl(lifetime) : 0;
109

    
110
  /* Copy the relevant part of the prefix */
111
  ip6_addr px_addr = ip6_hton(net6_prefix(rt->n.addr));
112
  memcpy(opt->prefix, &px_addr, 8 * px_blocks);
113

    
114
  /* Keeping track of first linger timeout */
115
  if (!rt->valid)
116
    ifa->valid_time = MIN(ifa->valid_time, rt->changed + ifa->cf->route_linger_time S);
117

    
118
  return 0;
119
}
120

    
121
static int
122
radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend)
123
{
124
  struct radv_rdnss_config *rcf = HEAD(*rdnss_list);
125

    
126
  while(NODE_VALID(rcf))
127
  {
128
    struct radv_rdnss_config *rcf_base = rcf;
129
    struct radv_opt_rdnss *op = (void *) *buf;
130
    int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip6_addr);
131
    int i = 0;
132

    
133
    if (max_i < 1)
134
      goto too_much;
135

    
136
    op->type = OPT_RDNSS;
137
    op->reserved = 0;
138

    
139
    if (rcf->lifetime_mult)
140
      op->lifetime = htonl(rcf->lifetime_mult * ifa->cf->max_ra_int);
141
    else
142
      op->lifetime = htonl(rcf->lifetime);
143

    
144
    while(NODE_VALID(rcf) &&
145
          (rcf->lifetime == rcf_base->lifetime) &&
146
          (rcf->lifetime_mult == rcf_base->lifetime_mult))
147
      {
148
        if (i >= max_i)
149
          goto too_much;
150

    
151
        op->servers[i] = ip6_hton(rcf->server);
152
        i++;
153

    
154
        rcf = NODE_NEXT(rcf);
155
      }
156

    
157
    op->length = 1+2*i;
158
    *buf += 8 * op->length;
159
  }
160

    
161
  return 0;
162

    
163
 too_much:
164
  log(L_WARN "%s: Too many RA options on interface %s",
165
      ifa->ra->p.name, ifa->iface->name);
166
  return -1;
167
}
168

    
169
int
170
radv_process_domain(struct radv_dnssl_config *cf)
171
{
172
  /* Format of domain in search list is <size> <label> <size> <label> ... 0 */
173

    
174
  char *dom = cf->domain;
175
  char *dom_end = dom; /* Just to  */
176
  u8 *dlen_save = &cf->dlen_first;
177
  uint len;
178

    
179
  while (dom_end)
180
  {
181
    dom_end = strchr(dom, '.');
182
    len = dom_end ? (uint)(dom_end - dom) : strlen(dom);
183

    
184
    if (len < 1 || len > 63)
185
      return -1;
186

    
187
    *dlen_save = len;
188
    dlen_save = (u8 *) dom_end;
189

    
190
    dom += len + 1;
191
  }
192

    
193
  len = dom - cf->domain;
194
  if (len > 254)
195
    return -1;
196

    
197
  cf->dlen_all = len;
198

    
199
  return 0;
200
}
201

    
202
static int
203
radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *bufend)
204
{
205
  struct radv_dnssl_config *dcf = HEAD(*dnssl_list);
206

    
207
  while(NODE_VALID(dcf))
208
  {
209
    struct radv_dnssl_config *dcf_base = dcf;
210
    struct radv_opt_dnssl *op = (void *) *buf;
211
    int bsize = bufend - *buf - sizeof(struct radv_opt_dnssl);
212
    int bpos = 0;
213

    
214
    if (bsize < 0)
215
      goto too_much;
216

    
217
    bsize = bsize & ~7; /* Round down to multiples of 8 */
218

    
219
    op->type = OPT_DNSSL;
220
    op->reserved = 0;
221

    
222
    if (dcf->lifetime_mult)
223
      op->lifetime = htonl(dcf->lifetime_mult * ifa->cf->max_ra_int);
224
    else
225
      op->lifetime = htonl(dcf->lifetime);
226

    
227
    while(NODE_VALID(dcf) &&
228
          (dcf->lifetime == dcf_base->lifetime) &&
229
          (dcf->lifetime_mult == dcf_base->lifetime_mult))
230
      {
231
        if (bpos + dcf->dlen_all + 1 > bsize)
232
          goto too_much;
233

    
234
        op->domain[bpos++] = dcf->dlen_first;
235
        memcpy(op->domain + bpos, dcf->domain, dcf->dlen_all);
236
        bpos += dcf->dlen_all;
237

    
238
        dcf = NODE_NEXT(dcf);
239
      }
240

    
241
    int blen = (bpos + 7) / 8;
242
    bzero(op->domain + bpos, 8 * blen - bpos);
243
    op->length = 1 + blen;
244
    *buf += 8 * op->length;
245
  }
246

    
247
  return 0;
248

    
249
 too_much:
250
  log(L_WARN "%s: Too many RA options on interface %s",
251
      ifa->ra->p.name, ifa->iface->name);
252
  return -1;
253
}
254

    
255
static int
256
radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px,
257
                    char **buf, char *bufend)
258
{
259
  struct radv_prefix_config *pc = px->cf;
260

    
261
  if (*buf + sizeof(struct radv_opt_prefix) > bufend)
262
  {
263
    log(L_WARN "%s: Too many prefixes on interface %s",
264
        ifa->ra->p.name, ifa->iface->name);
265
    return -1;
266
  }
267

    
268
  struct radv_opt_prefix *op = (void *) *buf;
269
  op->type = OPT_PREFIX;
270
  op->length = 4;
271
  op->pxlen = px->prefix.pxlen;
272
  op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
273
    (pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
274
  op->valid_lifetime = (ifa->ra->active || !pc->valid_lifetime_sensitive) ?
275
    htonl(pc->valid_lifetime) : 0;
276
  op->preferred_lifetime = (ifa->ra->active || !pc->preferred_lifetime_sensitive) ?
277
    htonl(pc->preferred_lifetime) : 0;
278
  op->reserved = 0;
279
  op->prefix = ip6_hton(px->prefix.prefix);
280
  *buf += sizeof(*op);
281

    
282
  /* Keeping track of first linger timeout */
283
  if (!px->valid)
284
    ifa->valid_time = MIN(ifa->valid_time, px->changed + ifa->cf->prefix_linger_time S);
285

    
286
  return 0;
287
}
288

    
289
static void
290
radv_prepare_ra(struct radv_iface *ifa)
291
{
292
  struct radv_proto *p = ifa->ra;
293
  struct radv_config *cf = (struct radv_config *) (p->p.cf);
294
  struct radv_iface_config *ic = ifa->cf;
295
  btime now = current_time();
296

    
297
  char *buf = ifa->sk->tbuf;
298
  char *bufstart = buf;
299
  char *bufend = buf + ifa->sk->tbsize;
300

    
301
  struct radv_ra_packet *pkt = (void *) buf;
302
  pkt->type = ICMPV6_RA;
303
  pkt->code = 0;
304
  pkt->checksum = 0;
305
  pkt->current_hop_limit = ic->current_hop_limit;
306
  pkt->router_lifetime = (p->valid && (p->active || !ic->default_lifetime_sensitive)) ?
307
    htons(ic->default_lifetime) : 0;
308
  pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
309
    (ic->other_config ? OPT_RA_OTHER_CFG : 0) |
310
    (pkt->router_lifetime ? ic->default_preference : 0);
311
  pkt->reachable_time = htonl(ic->reachable_time);
312
  pkt->retrans_timer = htonl(ic->retrans_timer);
313
  buf += sizeof(*pkt);
314

    
315
  if (ic->link_mtu)
316
  {
317
    struct radv_opt_mtu *om = (void *) buf;
318
    om->type = OPT_MTU;
319
    om->length = 1;
320
    om->reserved = 0;
321
    om->mtu = htonl(ic->link_mtu);
322
    buf += sizeof (*om);
323
  }
324

    
325
  /* Keeping track of first linger timeout */
326
  ifa->valid_time = TIME_INFINITY;
327

    
328
  struct radv_prefix *px;
329
  WALK_LIST(px, ifa->prefixes)
330
  {
331
    /* Skip invalid prefixes that are past linger timeout but still not pruned */
332
    if (!px->valid && ((px->changed + ic->prefix_linger_time S) <= now))
333
        continue;
334

    
335
    if (radv_prepare_prefix(ifa, px, &buf, bufend) < 0)
336
      goto done;
337
  }
338

    
339
  if (! ic->rdnss_local)
340
    if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0)
341
      goto done;
342

    
343
  if (radv_prepare_rdnss(ifa, &ic->rdnss_list, &buf, bufend) < 0)
344
    goto done;
345

    
346
  if (! ic->dnssl_local)
347
    if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0)
348
      goto done;
349

    
350
  if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0)
351
    goto done;
352

    
353
  if (p->fib_up)
354
  {
355
    FIB_WALK(&p->routes, struct radv_route, rt)
356
    {
357
      /* Skip invalid routes that are past linger timeout but still not pruned */
358
      if (!rt->valid && ((rt->changed + ic->route_linger_time S) <= now))
359
        continue;
360

    
361
      if (radv_prepare_route(ifa, rt, &buf, bufend) < 0)
362
        goto done;
363
    }
364
    FIB_WALK_END;
365
  }
366

    
367
 done:
368
  ifa->plen = buf - bufstart;
369
}
370

    
371

    
372
void
373
radv_send_ra(struct radv_iface *ifa)
374
{
375
  struct radv_proto *p = ifa->ra;
376

    
377
  /* We store prepared RA in tbuf */
378
  if (!ifa->plen)
379
    radv_prepare_ra(ifa);
380

    
381
  RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
382
  sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
383
}
384

    
385

    
386
static int
387
radv_rx_hook(sock *sk, uint size)
388
{
389
  struct radv_iface *ifa = sk->data;
390
  struct radv_proto *p = ifa->ra;
391

    
392
  /* We want just packets from sk->iface */
393
  if (sk->lifindex != sk->iface->index)
394
    return 1;
395

    
396
  if (ipa_equal(sk->faddr, sk->saddr))
397
    return 1;
398

    
399
  if (size < 8)
400
    return 1;
401

    
402
  byte *buf = sk->rbuf;
403

    
404
  if (buf[1] != 0)
405
    return 1;
406

    
407
  /* Validation is a bit sloppy - Hop Limit is not checked and
408
     length of options is ignored for RS and left to later for RA */
409

    
410
  switch (buf[0])
411
  {
412
  case ICMPV6_RS:
413
    RADV_TRACE(D_PACKETS, "Received RS from %I via %s",
414
               sk->faddr, ifa->iface->name);
415
    radv_iface_notify(ifa, RA_EV_RS);
416
    return 1;
417

    
418
  case ICMPV6_RA:
419
    RADV_TRACE(D_PACKETS, "Received RA from %I via %s",
420
               sk->faddr, ifa->iface->name);
421
    /* FIXME - there should be some checking of received RAs, but we just ignore them */
422
    return 1;
423

    
424
  default:
425
    return 1;
426
  }
427
}
428

    
429
static void
430
radv_tx_hook(sock *sk)
431
{
432
  struct radv_iface *ifa = sk->data;
433
  log(L_WARN "%s: TX hook called", ifa->ra->p.name);
434
}
435

    
436
static void
437
radv_err_hook(sock *sk, int err)
438
{
439
  struct radv_iface *ifa = sk->data;
440
  log(L_ERR "%s: Socket error on %s: %M", ifa->ra->p.name, ifa->iface->name, err);
441
}
442

    
443
int
444
radv_sk_open(struct radv_iface *ifa)
445
{
446
  sock *sk = sk_new(ifa->pool);
447
  sk->type = SK_IP;
448
  sk->subtype = SK_IPV6;
449
  sk->dport = ICMPV6_PROTO;
450
  sk->saddr = ifa->addr->ip;
451
  sk->vrf = ifa->ra->p.vrf;
452

    
453
  sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */
454
  sk->rx_hook = radv_rx_hook;
455
  sk->tx_hook = radv_tx_hook;
456
  sk->err_hook = radv_err_hook;
457
  sk->iface = ifa->iface;
458
  sk->rbsize = 1024; // bufsize(ifa);
459
  sk->tbsize = 1024; // bufsize(ifa);
460
  sk->data = ifa;
461
  sk->flags = SKF_LADDR_RX;
462

    
463
  if (sk_open(sk) < 0)
464
    goto err;
465

    
466
  /* We want listen just to ICMPv6 messages of type RS and RA */
467
  if (sk_set_icmp6_filter(sk, ICMPV6_RS, ICMPV6_RA) < 0)
468
    goto err;
469

    
470
  if (sk_setup_multicast(sk) < 0)
471
    goto err;
472

    
473
  if (sk_join_group(sk, IP6_ALL_ROUTERS) < 0)
474
    goto err;
475

    
476
  ifa->sk = sk;
477
  return 1;
478

    
479
 err:
480
  sk_log_error(sk, ifa->ra->p.name);
481
  rfree(sk);
482
  return 0;
483
}
484