Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / lib / flowspec.c @ 6b3f1a54

History | View | Annotate | Download (29.2 KB)

1
/*
2
 *        BIRD Library -- Flow specification (RFC 5575)
3
 *
4
 *        (c) 2016 CZ.NIC z.s.p.o.
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
/**
10
 * DOC: Flow specification (flowspec)
11
 *
12
 * Flowspec are rules (RFC 5575) for firewalls disseminated using BGP protocol.
13
 * The |flowspec.c| is a library for handling flowspec binary streams and
14
 * flowspec data structures. You will find there functions for validation
15
 * incoming flowspec binary streams, iterators for jumping over components,
16
 * functions for handling a length and functions for formatting flowspec data
17
 * structure into user-friendly text representation.
18
 *
19
 * In this library, you will find also flowspec builder. In |confbase.Y|, there
20
 * are grammar's rules for parsing and building new flowspec data structure
21
 * from BIRD's configuration files and from BIRD's command line interface.
22
 * Finalize function will assemble final &net_addr_flow4 or &net_addr_flow6
23
 * data structure.
24
 *
25
 * The data structures &net_addr_flow4 and &net_addr_flow6 are defined in
26
 * |net.h| file. The attribute length is size of whole data structure plus
27
 * binary stream representation of flowspec including a compressed encoded
28
 * length of flowspec.
29
 *
30
 * Sometimes in code, it is used expression flowspec type, it should mean
31
 * flowspec component type.
32
 */
33

    
34
#include "nest/bird.h"
35
#include "lib/flowspec.h"
36
#include "conf/conf.h"
37

    
38

    
39
static const char* flow4_type_str[] = {
40
  [FLOW_TYPE_DST_PREFIX]        = "dst",
41
  [FLOW_TYPE_SRC_PREFIX]        = "src",
42
  [FLOW_TYPE_IP_PROTOCOL]        = "proto",
43
  [FLOW_TYPE_PORT]                = "port",
44
  [FLOW_TYPE_DST_PORT]                = "dport",
45
  [FLOW_TYPE_SRC_PORT]                = "sport",
46
  [FLOW_TYPE_ICMP_TYPE]                = "icmp type",
47
  [FLOW_TYPE_ICMP_CODE]                = "icmp code",
48
  [FLOW_TYPE_TCP_FLAGS]                = "tcp flags",
49
  [FLOW_TYPE_PACKET_LENGTH]        = "length",
50
  [FLOW_TYPE_DSCP]                = "dscp",
51
  [FLOW_TYPE_FRAGMENT]                = "fragment"
52
};
53

    
54
static const char* flow6_type_str[] = {
55
  [FLOW_TYPE_DST_PREFIX]        = "dst",
56
  [FLOW_TYPE_SRC_PREFIX]        = "src",
57
  [FLOW_TYPE_NEXT_HEADER]        = "next header",
58
  [FLOW_TYPE_PORT]                = "port",
59
  [FLOW_TYPE_DST_PORT]                = "dport",
60
  [FLOW_TYPE_SRC_PORT]                = "sport",
61
  [FLOW_TYPE_ICMP_TYPE]                = "icmp type",
62
  [FLOW_TYPE_ICMP_CODE]                = "icmp code",
63
  [FLOW_TYPE_TCP_FLAGS]                = "tcp flags",
64
  [FLOW_TYPE_PACKET_LENGTH]        = "length",
65
  [FLOW_TYPE_DSCP]                = "dscp",
66
  [FLOW_TYPE_FRAGMENT]                = "fragment",
67
  [FLOW_TYPE_LABEL]                = "label"
68
};
69

    
70
/**
71
 * flow_type_str - get stringified flowspec name of component
72
 * @type: flowspec component type
73
 * @ipv6: IPv4/IPv6 decide flag, use zero for IPv4 and one for IPv6
74
 *
75
 * This function returns flowspec name of component @type in string.
76
 */
77
const char *
78
flow_type_str(enum flow_type type, int ipv6)
79
{
80
  return ipv6 ? flow6_type_str[type] : flow4_type_str[type];
81
}
82

    
83
/*
84
 *         Length
85
 */
86

    
87
/**
88
 * flow_write_length - write compressed length value
89
 * @data: destination buffer to write
90
 * @len: the value of the length (0 to 0xfff) for writing
91
 *
92
 * This function writes appropriate as (1- or 2-bytes) the value of @len into
93
 * buffer @data. The function returns number of written bytes, thus 1 or 2 bytes.
94
 */
95
uint
96
flow_write_length(byte *data, u16 len)
97
{
98
  if (len >= 0xf0)
99
  {
100
    put_u16(data, len | 0xf000);
101
    return 2;
102
  }
103

    
104
  *data = len;
105
  return 1;
106
}
107

    
108
inline static uint
109
get_value_length(const byte *op)
110
{
111
  return (1 << ((*op & 0x30) >> 4));
112
}
113

    
114

    
115

    
116
/*
117
 *        Flowspec iterators
118
 */
119

    
120
static inline u8  num_op(const byte *op)    { return  (*op & 0x07); }
121
static inline int isset_and(const byte *op) { return ((*op & 0x40) == 0x40); }
122
static inline int isset_end(const byte *op) { return ((*op & 0x80) == 0x80); }
123

    
124
static const byte *
125
flow_first_part(const byte *data)
126
{
127
  if (!data || flow_read_length(data) == 0)
128
    return NULL;
129

    
130
  /* It is allowed to encode the value of length less then 240 into 2-bytes too */
131
  if ((data[0] & 0xf0) == 0xf0)
132
    return data + 2;
133

    
134
  return data + 1;
135
}
136

    
137
/**
138
 * flow4_first_part - get position of the first flowspec component
139
 * @f: flowspec data structure &net_addr_flow4
140
 *
141
 * This function return a position to the beginning of the first flowspec
142
 * component in IPv4 flowspec @f.
143
 */
144
inline const byte *
145
flow4_first_part(const net_addr_flow4 *f)
146
{
147
  return f ? flow_first_part(f->data) : NULL;
148
}
149

    
150
/**
151
 * flow6_first_part - get position of the first flowspec component
152
 * @f: flowspec data structure &net_addr_flow6
153
 *
154
 * This function return a position to the beginning of the first flowspec
155
 * component in IPv6 flowspec @f.
156
 */
157
inline const byte *
158
flow6_first_part(const net_addr_flow6 *f)
159
{
160
  return f ? flow_first_part(f->data) : NULL;
161
}
162

    
163
static const byte *
164
flow_next_part(const byte *pos, const byte *end, int ipv6)
165
{
166
  switch (*pos++)
167
  {
168
  case FLOW_TYPE_DST_PREFIX:
169
  case FLOW_TYPE_SRC_PREFIX:
170
  {
171
    uint pxlen = *pos++;
172
    uint bytes = BYTES(pxlen);
173
    if (ipv6)
174
    {
175
      uint offset = *pos++ / 8;
176
      pos += bytes - offset;
177
    }
178
    else
179
    {
180
      pos += bytes;
181
    }
182
    break;
183
  }
184

    
185
  case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
186
  case FLOW_TYPE_PORT:
187
  case FLOW_TYPE_DST_PORT:
188
  case FLOW_TYPE_SRC_PORT:
189
  case FLOW_TYPE_ICMP_TYPE:
190
  case FLOW_TYPE_ICMP_CODE:
191
  case FLOW_TYPE_TCP_FLAGS:
192
  case FLOW_TYPE_PACKET_LENGTH:
193
  case FLOW_TYPE_DSCP:
194
  case FLOW_TYPE_FRAGMENT:
195
  case FLOW_TYPE_LABEL:
196
  {
197
    /* Is this the end of list operator-value pair? */
198
    uint last = 0;
199

    
200
    while (!last)
201
    {
202
      last = isset_end(pos);
203

    
204
      /* Value length of operator */
205
      uint len = get_value_length(pos);
206
      pos += 1+len;
207
    }
208
    break;
209
  }
210
  default:
211
    return NULL;
212
  }
213

    
214
  return (pos < end) ? pos : NULL;
215
}
216

    
217
/**
218
 * flow4_next_part - an iterator over flowspec components in flowspec binary stream
219
 * @pos: the beginning of a previous or the first component in flowspec binary
220
 *       stream
221
 * @end: the last valid byte in scanned flowspec binary stream
222
 *
223
 * This function returns a position to the beginning of the next component
224
 * (to a component type byte) in flowspec binary stream or %NULL for the end.
225
 */
226
inline const byte *
227
flow4_next_part(const byte *pos, const byte *end)
228
{
229
  return flow_next_part(pos, end, 0);
230
}
231

    
232
/**
233
 * flow6_next_part - an iterator over flowspec components in flowspec binary stream
234
 * @pos: the beginning of a previous or the first component in flowspec binary
235
 *       stream
236
 * @end: the last valid byte in scanned flowspec binary stream
237
 *
238
 * This function returns a position to the beginning of the next component
239
 * (to a component type byte) in flowspec binary stream or %NULL for the end.
240
 */
241
inline const byte *
242
flow6_next_part(const byte *pos, const byte *end)
243
{
244
  return flow_next_part(pos, end, 1);
245
}
246

    
247

    
248
/*
249
 *         Flowspec validation
250
 */
251

    
252
static const char* flow_validated_state_str_[] = {
253
  [FLOW_ST_UNKNOWN_COMPONENT]                 = "Unknown component",
254
  [FLOW_ST_VALID]                         = "Valid",
255
  [FLOW_ST_NOT_COMPLETE]                 = "Not complete",
256
  [FLOW_ST_EXCEED_MAX_PREFIX_LENGTH]         = "Exceed maximal prefix length",
257
  [FLOW_ST_EXCEED_MAX_PREFIX_OFFSET]        = "Exceed maximal prefix offset",
258
  [FLOW_ST_EXCEED_MAX_VALUE_LENGTH]        = "Exceed maximal value length",
259
  [FLOW_ST_BAD_TYPE_ORDER]                 = "Bad component order",
260
  [FLOW_ST_AND_BIT_SHOULD_BE_UNSET]         = "The AND-bit should be unset",
261
  [FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED]         = "The Zero-bit should be unset",
262
  [FLOW_ST_DEST_PREFIX_REQUIRED]         = "Destination prefix is missing",
263
  [FLOW_ST_INVALID_TCP_FLAGS]                = "TCP flags exceeding 0xfff",
264
  [FLOW_ST_CANNOT_USE_DONT_FRAGMENT]    = "Cannot use Don't fragment flag in IPv6 flow"
265
};
266

    
267
/**
268
 * flow_validated_state_str - return a textual description of validation process
269
 * @code: validation result
270
 *
271
 * This function return well described validation state in string.
272
 */
273
const char *
274
flow_validated_state_str(enum flow_validated_state code)
275
{
276
  return flow_validated_state_str_[code];
277
}
278

    
279
static const u8 flow4_max_value_length[] = {
280
  [FLOW_TYPE_DST_PREFIX]        = 0,
281
  [FLOW_TYPE_SRC_PREFIX]        = 0,
282
  [FLOW_TYPE_IP_PROTOCOL]        = 1,
283
  [FLOW_TYPE_PORT]                = 2,
284
  [FLOW_TYPE_DST_PORT]                = 2,
285
  [FLOW_TYPE_SRC_PORT]                = 2,
286
  [FLOW_TYPE_ICMP_TYPE]                = 1,
287
  [FLOW_TYPE_ICMP_CODE]                = 1,
288
  [FLOW_TYPE_TCP_FLAGS]                = 2,
289
  [FLOW_TYPE_PACKET_LENGTH]        = 2,
290
  [FLOW_TYPE_DSCP]                = 1,
291
  [FLOW_TYPE_FRAGMENT]                = 1        /* XXX */
292
};
293

    
294
static const u8 flow6_max_value_length[] = {
295
  [FLOW_TYPE_DST_PREFIX]        = 0,
296
  [FLOW_TYPE_SRC_PREFIX]        = 0,
297
  [FLOW_TYPE_NEXT_HEADER]        = 1,
298
  [FLOW_TYPE_PORT]                = 2,
299
  [FLOW_TYPE_DST_PORT]                = 2,
300
  [FLOW_TYPE_SRC_PORT]                = 2,
301
  [FLOW_TYPE_ICMP_TYPE]                = 1,
302
  [FLOW_TYPE_ICMP_CODE]                = 1,
303
  [FLOW_TYPE_TCP_FLAGS]                = 2,
304
  [FLOW_TYPE_PACKET_LENGTH]        = 2,
305
  [FLOW_TYPE_DSCP]                = 1,
306
  [FLOW_TYPE_FRAGMENT]                = 1,        /* XXX */
307
  [FLOW_TYPE_LABEL]                = 4
308
};
309

    
310
static u8
311
flow_max_value_length(enum flow_type type, int ipv6)
312
{
313
  return ipv6 ? flow6_max_value_length[type] : flow4_max_value_length[type];
314
}
315

    
316
/**
317
 * flow_check_cf_bmk_values - check value/bitmask part of flowspec component
318
 * @fb: flow builder instance
319
 * @neg: negation operand
320
 * @val: value from value/mask pair
321
 * @mask: bitmap mask from value/mask pair
322
 *
323
 * This function checks value/bitmask pair. If some problem will appear, the
324
 * function calls cf_error() function with a textual description of reason
325
 * to failing of validation.
326
 */
327
void
328
flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask)
329
{
330
  flow_check_cf_value_length(fb, val);
331
  flow_check_cf_value_length(fb, mask);
332

    
333
  if (neg && !(val == 0 || val == mask))
334
    cf_error("For negation, value must be zero or bitmask");
335

    
336
  if ((fb->this_type == FLOW_TYPE_TCP_FLAGS) && (mask & 0xf000))
337
    cf_error("Invalid mask 0x%x, must not exceed 0xfff", mask);
338

    
339
  if ((fb->this_type == FLOW_TYPE_FRAGMENT) && fb->ipv6 && (mask & 0x01))
340
    cf_error("Invalid mask 0x%x, bit 0 must be 0", mask);
341

    
342
  if (val & ~mask)
343
    cf_error("Value 0x%x outside bitmask 0x%x", val, mask);
344
}
345

    
346
/**
347
 * flow_check_cf_value_length - check value by flowspec component type
348
 * @fb: flow builder instance
349
 * @val: value
350
 *
351
 * This function checks if the value is in range of component's type support.
352
 * If some problem will appear, the function calls cf_error() function with
353
 * a textual description of reason to failing of validation.
354
 */
355
void
356
flow_check_cf_value_length(struct flow_builder *fb, u32 val)
357
{
358
  enum flow_type t = fb->this_type;
359
  u8 max = flow_max_value_length(t, fb->ipv6);
360

    
361
  if (t == FLOW_TYPE_DSCP && val > 0x3f)
362
    cf_error("%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val);
363

    
364
  if (max == 1 && (val > 0xff))
365
    cf_error("%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), val);
366

    
367
  if (max == 2 && (val > 0xffff))
368
    cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val);
369
}
370

    
371
static enum flow_validated_state
372
flow_validate(const byte *nlri, uint len, int ipv6)
373
{
374
  enum flow_type type = 0;
375
  const byte *pos = nlri;
376
  const byte *end = nlri + len;
377
  int met_dst_pfx = 0;
378

    
379
  while (pos < end)
380
  {
381
    /* Check increasing type ordering */
382
    if (*pos <= type)
383
      return FLOW_ST_BAD_TYPE_ORDER;
384
    type = *pos++;
385

    
386
    switch (type)
387
    {
388
    case FLOW_TYPE_DST_PREFIX:
389
      met_dst_pfx = 1;
390
      /* Fall through */
391
    case FLOW_TYPE_SRC_PREFIX:
392
    {
393
      uint pxlen = *pos++;
394
      if (pxlen > (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
395
        return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
396

    
397
      uint bytes = BYTES(pxlen);
398
      if (ipv6)
399
      {
400
        uint pxoffset = *pos++;
401
        if (pxoffset > IP6_MAX_PREFIX_LENGTH || pxoffset > pxlen)
402
          return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
403
        bytes -= pxoffset / 8;
404
      }
405
      pos += bytes;
406

    
407
      break;
408
    }
409

    
410
    case FLOW_TYPE_LABEL:
411
      if (!ipv6)
412
        return FLOW_ST_UNKNOWN_COMPONENT;
413
      /* fall through */
414
    case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
415
    case FLOW_TYPE_PORT:
416
    case FLOW_TYPE_DST_PORT:
417
    case FLOW_TYPE_SRC_PORT:
418
    case FLOW_TYPE_ICMP_TYPE:
419
    case FLOW_TYPE_ICMP_CODE:
420
    case FLOW_TYPE_TCP_FLAGS:
421
    case FLOW_TYPE_PACKET_LENGTH:
422
    case FLOW_TYPE_DSCP:
423
    case FLOW_TYPE_FRAGMENT:
424
    {
425
      uint last = 0;
426
      uint first = 1;
427

    
428
      while (!last)
429
      {
430
        /*
431
         *    0   1   2   3   4   5   6   7
432
         *  +---+---+---+---+---+---+---+---+
433
         *  | e | a |  len  | 0 |lt |gt |eq |
434
         *  +---+---+---+---+---+---+---+---+
435
         *
436
         *           Numeric operator
437
         */
438

    
439
        last = isset_end(pos);
440

    
441
        /* The AND bit should in the first operator byte of a sequence */
442
        if (first && isset_and(pos))
443
          return FLOW_ST_AND_BIT_SHOULD_BE_UNSET;
444

    
445
        /* This bit should be zero */
446
        if (*pos & 0x08)
447
          return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
448

    
449
        if (type == FLOW_TYPE_TCP_FLAGS || type == FLOW_TYPE_FRAGMENT)
450
        {
451
          /*
452
           *    0   1   2   3   4   5   6   7
453
           *  +---+---+---+---+---+---+---+---+
454
           *  | e | a |  len  | 0 | 0 |not| m |
455
           *  +---+---+---+---+---+---+---+---+
456
           *
457
           *           Bitmask operand
458
           */
459
          if (*pos & 0x04)
460
            return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
461
        }
462

    
463
        /* Value length of operator */
464
        uint len = get_value_length(pos);
465
        if (len > flow_max_value_length(type, ipv6))
466
          return FLOW_ST_EXCEED_MAX_VALUE_LENGTH;
467

    
468
        /* TCP Flags component must not check highest nibble (just 12 valid bits) */
469
        if ((type == FLOW_TYPE_TCP_FLAGS) && (len == 2) && (pos[1] & 0xf0))
470
          return FLOW_ST_INVALID_TCP_FLAGS;
471

    
472
        /* Bit-7 must be 0 [draft-ietf-idr-flow-spec-v6] */
473
        if ((type == FLOW_TYPE_FRAGMENT) && ipv6 && (pos[1] & 0x01))
474
          return FLOW_ST_CANNOT_USE_DONT_FRAGMENT;
475
        /* XXX: Could be a fragment component encoded in 2-bytes? */
476

    
477
        pos += 1+len;
478

    
479
        if (pos > end && !last)
480
          return FLOW_ST_NOT_COMPLETE;
481

    
482
        if (pos > (end+1))
483
          return FLOW_ST_NOT_COMPLETE;
484

    
485
        first = 0;
486
      }
487
      break;
488
    }
489
    default:
490
      return FLOW_ST_UNKNOWN_COMPONENT;
491
    }
492
  }
493

    
494
  if (pos != end)
495
    return FLOW_ST_NOT_COMPLETE;
496

    
497
  if (!ipv6 && !met_dst_pfx)
498
    return FLOW_ST_DEST_PREFIX_REQUIRED;
499

    
500
  return FLOW_ST_VALID;
501
}
502

    
503
/**
504
 * flow4_validate - check untrustworthy IPv4 flowspec data stream
505
 * @nlri: flowspec data stream without compressed encoded length value
506
 * @len: length of @nlri
507
 *
508
 * This function checks meaningfulness of binary flowspec. It should return
509
 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
510
 * returns some other %FLOW_ST_xxx state.
511
 */
512
inline enum flow_validated_state
513
flow4_validate(const byte *nlri, uint len)
514
{
515
  return flow_validate(nlri, len, 0);
516
}
517

    
518
/**
519
 * flow6_validate - check untrustworthy IPv6 flowspec data stream
520
 * @nlri: flowspec binary stream without encoded length value
521
 * @len: length of @nlri
522
 *
523
 * This function checks meaningfulness of binary flowspec. It should return
524
 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
525
 * returns some other %FLOW_ST_xxx state.
526
 */
527
inline enum flow_validated_state
528
flow6_validate(const byte *nlri, uint len)
529
{
530
  return flow_validate(nlri, len, 1);
531
}
532

    
533
/**
534
 * flow4_validate_cf - validate flowspec data structure &net_addr_flow4 in parsing time
535
 * @f: flowspec data structure &net_addr_flow4
536
 *
537
 * Check if @f is valid flowspec data structure. Can call cf_error() function
538
 * with a textual description of reason to failing of validation.
539
 */
540
void
541
flow4_validate_cf(net_addr_flow4 *f)
542
{
543
  enum flow_validated_state r = flow4_validate(flow4_first_part(f), flow_read_length(f->data));
544

    
545
  if (r != FLOW_ST_VALID)
546
    cf_error("Invalid flow route: %s", flow_validated_state_str(r));
547
}
548

    
549
/**
550
 * flow6_validate_cf - validate flowspec data structure &net_addr_flow6 in parsing time
551
 * @f: flowspec data structure &net_addr_flow6
552
 *
553
 * Check if @f is valid flowspec data structure. Can call cf_error() function
554
 * with a textual description of reason to failing of validation.
555
 */
556
void
557
flow6_validate_cf(net_addr_flow6 *f)
558
{
559
  enum flow_validated_state r = flow6_validate(flow6_first_part(f), flow_read_length(f->data));
560

    
561
  if (r != FLOW_ST_VALID)
562
    cf_error("Invalid flow route: %s", flow_validated_state_str(r));
563
}
564

    
565

    
566
/*
567
 *         Flowspec Builder
568
 */
569

    
570
/**
571
 * flow_builder_init - constructor for flowspec builder instance
572
 * @pool: memory pool
573
 *
574
 * This function prepares flowspec builder instance using memory pool @pool.
575
 */
576
struct flow_builder *
577
flow_builder_init(pool *pool)
578
{
579
  struct flow_builder *fb = mb_allocz(pool, sizeof(struct flow_builder));
580
  BUFFER_INIT(fb->data, pool, 4);
581
  return fb;
582
}
583

    
584
static int
585
is_stackable_type(enum flow_type type)
586
{
587
  switch (type)
588
  {
589
  case FLOW_TYPE_IP_PROTOCOL:
590
  case FLOW_TYPE_PORT:
591
  case FLOW_TYPE_DST_PORT:
592
  case FLOW_TYPE_SRC_PORT:
593
  case FLOW_TYPE_ICMP_TYPE:
594
  case FLOW_TYPE_ICMP_CODE:
595
  case FLOW_TYPE_TCP_FLAGS:
596
  case FLOW_TYPE_PACKET_LENGTH:
597
  case FLOW_TYPE_DSCP:
598
  case FLOW_TYPE_FRAGMENT:
599
  case FLOW_TYPE_LABEL:
600
    return 1;
601

    
602
  default:
603
    /* The unknown components are not stack-able in default */
604
    return 0;
605
  }
606
}
607

    
608
static int
609
builder_add_prepare(struct flow_builder *fb)
610
{
611
  if (fb->parts[fb->this_type].length)
612
  {
613
    if (fb->last_type != fb->this_type)
614
      return 0;
615

    
616
    if (!is_stackable_type(fb->this_type))
617
      return 0;
618
  }
619
  else
620
  {
621
    fb->parts[fb->this_type].offset = fb->data.used;
622
  }
623

    
624
  return 1;
625
}
626

    
627
static void
628
builder_add_finish(struct flow_builder *fb)
629
{
630
  fb->parts[fb->this_type].length = fb->data.used - fb->parts[fb->this_type].offset;
631
  flow_builder_set_type(fb, fb->this_type);
632
}
633

    
634
static void
635
push_pfx_to_buffer(struct flow_builder *fb, u8 pxlen_bytes, byte *ip)
636
{
637
  for (int i = 0; i < pxlen_bytes; i++)
638
    BUFFER_PUSH(fb->data) = *ip++;
639
}
640

    
641
/**
642
 * flow_builder4_add_pfx - add IPv4 prefix
643
 * @fb: flowspec builder instance
644
 * @n4: net address of type IPv4
645
 *
646
 * This function add IPv4 prefix into flowspec builder instance.
647
 */
648
int
649
flow_builder4_add_pfx(struct flow_builder *fb, const net_addr_ip4 *n4)
650
{
651
  if (!builder_add_prepare(fb))
652
    return 0;
653

    
654
  ip4_addr ip4 = ip4_hton(n4->prefix);
655

    
656
  BUFFER_PUSH(fb->data) = fb->this_type;
657
  BUFFER_PUSH(fb->data) = n4->pxlen;
658
  push_pfx_to_buffer(fb, BYTES(n4->pxlen), (byte *) &ip4);
659

    
660
  builder_add_finish(fb);
661
  return 1;
662
}
663

    
664
/**
665
 * flow_builder6_add_pfx - add IPv6 prefix
666
 * @fb: flowspec builder instance
667
 * @n6: net address of type IPv4
668
 * @pxoffset: prefix offset for @n6
669
 *
670
 * This function add IPv4 prefix into flowspec builder instance. This function
671
 * should return 1 for successful adding, otherwise returns %0.
672
 */
673
int
674
flow_builder6_add_pfx(struct flow_builder *fb, const net_addr_ip6 *n6, u32 pxoffset)
675
{
676
  if (!builder_add_prepare(fb))
677
    return 0;
678

    
679
  ip6_addr ip6 = ip6_hton(n6->prefix);
680

    
681
  BUFFER_PUSH(fb->data) = fb->this_type;
682
  BUFFER_PUSH(fb->data) = n6->pxlen;
683
  BUFFER_PUSH(fb->data) = pxoffset;
684
  push_pfx_to_buffer(fb, BYTES(n6->pxlen) - (pxoffset / 8), ((byte *) &ip6) + (pxoffset / 8));
685

    
686
  builder_add_finish(fb);
687
  return 1;
688
}
689

    
690
/**
691
 * flow_builder_add_op_val - add operator/value pair
692
 * @fb: flowspec builder instance
693
 * @op: operator
694
 * @value: value
695
 *
696
 * This function add operator/value pair as a part of a flowspec component. It
697
 * is required to set appropriate flowspec component type using function
698
 * flow_builder_set_type(). This function should return 1 for successful
699
 * adding, otherwise returns 0.
700
 */
701
int
702
flow_builder_add_op_val(struct flow_builder *fb, byte op, u32 value)
703
{
704
  if (!builder_add_prepare(fb))
705
    return 0;
706

    
707
  if (fb->this_type == fb->last_type)
708
  {
709
    /* Remove the end-bit from last operand-value pair of the component */
710
    fb->data.data[fb->last_op_offset] &= 0x7f;
711
  }
712
  else
713
  {
714
    BUFFER_PUSH(fb->data) = fb->this_type;
715
  }
716

    
717
  fb->last_op_offset = fb->data.used;
718

    
719
  /* Set the end-bit for operand-value pair of the component */
720
  op |= 0x80;
721

    
722
  if (value & 0xff00)
723
  {
724
    BUFFER_PUSH(fb->data) = op | 0x10;
725
    put_u16(BUFFER_INC(fb->data, 2), value);
726
  }
727
  else
728
  {
729
    BUFFER_PUSH(fb->data) = op;
730
    BUFFER_PUSH(fb->data) = (u8) value;
731
  }
732

    
733
  builder_add_finish(fb);
734
  return 1;
735
}
736

    
737
/**
738
 * flow_builder_add_val_mask - add value/bitmask pair
739
 * @fb: flowspec builder instance
740
 * @op: operator
741
 * @value: value
742
 * @mask: bitmask
743
 *
744
 * It is required to set appropriate flowspec component type using function
745
 * flow_builder_set_type(). This function should return 1 for successful adding,
746
 * otherwise returns 0.
747
 */
748
int
749
flow_builder_add_val_mask(struct flow_builder *fb, byte op, u32 value, u32 mask)
750
{
751
  u32 a =  value & mask;
752
  u32 b = ~value & mask;
753

    
754
  if (a)
755
  {
756
    flow_builder_add_op_val(fb, op ^ 0x01, a);
757
    op |= FLOW_OP_AND;
758
  }
759

    
760
  if (b)
761
    flow_builder_add_op_val(fb, op ^ 0x02, b);
762

    
763
  return 1;
764
}
765

    
766

    
767
/**
768
 * flow_builder_set_type - set type of next flowspec component
769
 * @fb: flowspec builder instance
770
 * @type: flowspec component type
771
 *
772
 * This function sets type of next flowspec component. It is necessary to call
773
 * this function before each changing of adding flowspec component.
774
 */
775
void
776
flow_builder_set_type(struct flow_builder *fb, enum flow_type type)
777
{
778
  fb->last_type = fb->this_type;
779
  fb->this_type = type;
780
}
781

    
782
static ip4_addr
783
flow_read_ip4(const byte *px, uint pxlen)
784
{
785
  ip4_addr ip = IP4_NONE;
786
  memcpy(&ip, px, BYTES(pxlen));
787
  return ip4_ntoh(ip);
788
}
789

    
790
static ip6_addr
791
flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
792
{
793
  uint floor_offset = BYTES(pxoffset - (pxoffset % 8));
794
  uint ceil_len = BYTES(pxlen);
795
  ip6_addr ip = IP6_NONE;
796

    
797
  memcpy(((byte *) &ip) + floor_offset, px, ceil_len - floor_offset);
798

    
799
  return ip6_ntoh(ip);
800
}
801

    
802
static void
803
builder_write_parts(struct flow_builder *fb, byte *buf)
804
{
805
  for (int i = 1; i < FLOW_TYPE_MAX; i++)
806
  {
807
    if (fb->parts[i].length)
808
    {
809
      memcpy(buf, fb->data.data + fb->parts[i].offset, fb->parts[i].length);
810
      buf += fb->parts[i].length;
811
    }
812
  }
813
}
814

    
815
/**
816
 * flow_builder4_finalize - assemble final flowspec data structure &net_addr_flow4
817
 * @fb: flowspec builder instance
818
 * @lpool: linear memory pool
819
 *
820
 * This function returns final flowspec data structure &net_addr_flow4 allocated
821
 * onto @lpool linear memory pool.
822
 */
823
net_addr_flow4 *
824
flow_builder4_finalize(struct flow_builder *fb, linpool *lpool)
825
{
826
  uint data_len = fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
827
  net_addr_flow4 *f = lp_alloc(lpool, sizeof(struct net_addr_flow4) + data_len);
828

    
829
  ip4_addr prefix = IP4_NONE;
830
  uint pxlen = 0;
831

    
832
  if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
833
  {
834
    byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
835
    pxlen = *p++;
836
    prefix = flow_read_ip4(p, pxlen);
837
  }
838
  *f = NET_ADDR_FLOW4(prefix, pxlen, data_len);
839

    
840
  builder_write_parts(fb, f->data + flow_write_length(f->data, fb->data.used));
841

    
842
  return f;
843
}
844

    
845
/**
846
 * flow_builder6_finalize - assemble final flowspec data structure &net_addr_flow6
847
 * @fb: flowspec builder instance
848
 * @lpool: linear memory pool for allocation of
849
 *
850
 * This function returns final flowspec data structure &net_addr_flow6 allocated
851
 * onto @lpool linear memory pool.
852
 */
853
net_addr_flow6 *
854
flow_builder6_finalize(struct flow_builder *fb, linpool *lpool)
855
{
856
  uint data_len =  fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
857
  net_addr_flow6 *n = lp_alloc(lpool, sizeof(net_addr_flow6) + data_len);
858

    
859
  ip6_addr prefix = IP6_NONE;
860
  uint pxlen = 0;
861

    
862
  if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
863
  {
864
    byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
865
    pxlen = *p++;
866
    uint pxoffset = *p++;
867
    prefix = flow_read_ip6(p, pxlen, pxoffset);
868
  }
869
  *n = NET_ADDR_FLOW6(prefix, pxlen, data_len);
870

    
871
  builder_write_parts(fb, n->data + flow_write_length(n->data, fb->data.used));
872

    
873
  return n;
874
}
875

    
876
/**
877
 * flow_builder_clear - flush flowspec builder instance for another flowspec creation
878
 * @fb: flowspec builder instance
879
 *
880
 * This function flushes all data from builder but it maintains pre-allocated
881
 * buffer space.
882
 */
883
void
884
flow_builder_clear(struct flow_builder *fb)
885
{
886
  BUFFER(byte) data;
887
  BUFFER_FLUSH(fb->data);
888

    
889
  BUFFER_SHALLOW_COPY(data, fb->data);
890
  memset(fb, 0, sizeof(struct flow_builder));
891
  BUFFER_SHALLOW_COPY(fb->data, data);
892
}
893

    
894

    
895
/*
896
 *         Net Formatting
897
 */
898

    
899
/* Flowspec operators for [op, value]+ pairs */
900

    
901
static const char *
902
num_op_str(const byte *op)
903
{
904
  switch (*op & 0x07)
905
  {
906
  case FLOW_OP_TRUE:        return "true";
907
  case FLOW_OP_EQ:        return "=";
908
  case FLOW_OP_GT:        return ">";
909
  case FLOW_OP_GEQ:        return ">=";
910
  case FLOW_OP_LT:        return "<";
911
  case FLOW_OP_LEQ:        return "<=";
912
  case FLOW_OP_NEQ:        return "!=";
913
  case FLOW_OP_FALSE:        return "false";
914
  }
915

    
916
  return NULL;
917
}
918

    
919
static uint
920
get_value(const byte *val, u8 len)
921
{
922
  switch (len)
923
  {
924
  case 1: return *val;
925
  case 2: return get_u16(val);
926
  case 4: return get_u32(val);
927
  // No component may have length 8
928
  // case 8: return get_u64(val);
929
  }
930

    
931
  return 0;
932
}
933

    
934
static const char *
935
fragment_val_str(u8 val)
936
{
937
  switch (val)
938
  {
939
  case 1: return "dont_fragment";
940
  case 2: return "is_fragment";
941
  case 4: return "first_fragment";
942
  case 8: return "last_fragment";
943
  }
944
  return "???";
945
}
946

    
947
static void
948
net_format_flow_ip(buffer *b, const byte *part, int ipv6)
949
{
950
  uint pxlen = *(part+1);
951
  if (ipv6)
952
  {
953
    uint pxoffset = *(part+2);
954
    if (pxoffset)
955
      buffer_print(b, "%I6/%u offset %u; ", flow_read_ip6(part+3,pxlen,pxoffset), pxlen, pxoffset);
956
    else
957
      buffer_print(b, "%I6/%u; ", flow_read_ip6(part+3,pxlen,0), pxlen);
958
  }
959
  else
960
  {
961
    buffer_print(b, "%I4/%u; ", flow_read_ip4(part+2,pxlen), pxlen);
962
  }
963
}
964

    
965
static void
966
net_format_flow_num(buffer *b, const byte *part)
967
{
968
  const byte *last_op = NULL;
969
  const byte *op = part+1;
970
  uint val;
971
  uint len;
972
  uint first = 1;
973

    
974
  while (1)
975
  {
976
    if (!first)
977
    {
978
      /* XXX: I don't like this so complicated if-tree */
979
      if (!isset_and(op) &&
980
          ((num_op(     op) == FLOW_OP_EQ) || (num_op(     op) == FLOW_OP_GEQ)) &&
981
          ((num_op(last_op) == FLOW_OP_EQ) || (num_op(last_op) == FLOW_OP_LEQ)))
982
      {
983
        b->pos--; /* Remove last char (it is a space) */
984
        buffer_puts(b, ",");
985
      }
986
      else
987
      {
988
        buffer_puts(b, isset_and(op) ? "&& " : "|| ");
989
      }
990
    }
991
    first = 0;
992

    
993
    len = get_value_length(op);
994
    val = get_value(op+1, len);
995

    
996
    if (!isset_end(op) && !isset_and(op) && isset_and(op+1+len) &&
997
        (num_op(op) == FLOW_OP_GEQ) && (num_op(op+1+len) == FLOW_OP_LEQ))
998
    {
999
      /* Display interval */
1000
      buffer_print(b, "%u..", val);
1001
      op += 1 + len;
1002
      len = get_value_length(op);
1003
      val = get_value(op+1, len);
1004
      buffer_print(b, "%u", val);
1005
    }
1006
    else if (num_op(op) == FLOW_OP_EQ)
1007
    {
1008
      buffer_print(b, "%u", val);
1009
    }
1010
    else
1011
    {
1012
      buffer_print(b, "%s %u", num_op_str(op), val);
1013
    }
1014

    
1015
    if (isset_end(op))
1016
    {
1017
      buffer_puts(b, "; ");
1018
      break;
1019
    }
1020
    else
1021
    {
1022
      buffer_puts(b, " ");
1023
    }
1024

    
1025
    last_op = op;
1026
    op += 1 + len;
1027
  }
1028
}
1029

    
1030
static void
1031
net_format_flow_bitmask(buffer *b, const byte *part)
1032
{
1033
  const byte *op = part+1;
1034
  uint val;
1035
  uint len;
1036
  uint first = 1;
1037

    
1038
  while (1)
1039
  {
1040
    if (!first)
1041
    {
1042
      if (isset_and(op))
1043
      {
1044
        b->pos--; /* Remove last char (it is a space) */
1045
        buffer_puts(b, ",");
1046
      }
1047
      else
1048
      {
1049
        buffer_puts(b, "|| ");
1050
      }
1051
    }
1052
    first = 0;
1053

    
1054
    len = get_value_length(op);
1055
    val = get_value(op+1, len);
1056

    
1057
    /*
1058
     *   Not Match  Show
1059
     *  ------------------
1060
     *    0    0    !0/B
1061
     *    0    1     B/B
1062
     *    1    0     0/B
1063
     *    1    1    !B/B
1064
     */
1065

    
1066
    if ((*op & 0x3) == 0x3 || (*op & 0x3) == 0)
1067
      buffer_puts(b, "!");
1068

    
1069
    if (*part == FLOW_TYPE_FRAGMENT && (val == 1 || val == 2 || val == 4 || val == 8))
1070
      buffer_print(b, "%s%s", ((*op & 0x1) ? "" : "!"), fragment_val_str(val));
1071
    else
1072
      buffer_print(b, "0x%x/0x%x", ((*op & 0x1) ? val : 0), val);
1073

    
1074
    if (isset_end(op))
1075
    {
1076
      buffer_puts(b, "; ");
1077
      break;
1078
    }
1079
    else
1080
    {
1081
      buffer_puts(b, " ");
1082
    }
1083

    
1084
    op += 1 + len;
1085
  }
1086
}
1087

    
1088
static uint
1089
net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
1090
{
1091
  buffer b = {
1092
    .start = buf,
1093
    .pos = buf,
1094
    .end = buf + blen,
1095
  };
1096

    
1097
  const byte *part = flow_first_part(data);
1098
  *buf = 0;
1099

    
1100
  if (ipv6)
1101
    buffer_puts(&b, "flow6 { ");
1102
  else
1103
    buffer_puts(&b, "flow4 { ");
1104

    
1105
  while (part)
1106
  {
1107
    buffer_print(&b, "%s ", flow_type_str(*part, ipv6));
1108

    
1109
    switch (*part)
1110
    {
1111
    case FLOW_TYPE_DST_PREFIX:
1112
    case FLOW_TYPE_SRC_PREFIX:
1113
      net_format_flow_ip(&b, part, ipv6);
1114
      break;
1115
    case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
1116
    case FLOW_TYPE_PORT:
1117
    case FLOW_TYPE_DST_PORT:
1118
    case FLOW_TYPE_SRC_PORT:
1119
    case FLOW_TYPE_ICMP_TYPE:
1120
    case FLOW_TYPE_ICMP_CODE:
1121
    case FLOW_TYPE_PACKET_LENGTH:
1122
    case FLOW_TYPE_DSCP:
1123
      net_format_flow_num(&b, part);
1124
      break;
1125
    case FLOW_TYPE_TCP_FLAGS:
1126
    case FLOW_TYPE_FRAGMENT:
1127
    case FLOW_TYPE_LABEL:
1128
      net_format_flow_bitmask(&b, part);
1129
      break;
1130
    }
1131

    
1132
    part = flow_next_part(part, data+dlen, ipv6);
1133
  }
1134

    
1135
  buffer_puts(&b, "}");
1136

    
1137
  if (b.pos == b.end)
1138
  {
1139
    b.pos = b.start + MIN(blen - 6, strlen(b.start));
1140
    buffer_puts(&b, " ...}");
1141
  }
1142

    
1143
  return b.pos - b.start;
1144
}
1145

    
1146
/**
1147
 * flow4_net_format - stringify flowspec data structure &net_addr_flow4
1148
 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1149
 * @blen: free allocated space in @buf
1150
 * @f: flowspec data structure &net_addr_flow4 for stringify
1151
 *
1152
 * This function writes stringified @f into @buf. The function returns number
1153
 * of written chars. If final string is too large, the string will ends the with
1154
 * ' ...}' sequence and zero-terminator.
1155
 */
1156
uint
1157
flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f)
1158
{
1159
  return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow4), 0);
1160
}
1161

    
1162
/**
1163
 * flow6_net_format - stringify flowspec data structure &net_addr_flow6
1164
 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1165
 * @blen: free allocated space in @buf
1166
 * @f: flowspec data structure &net_addr_flow4 for stringify
1167
 *
1168
 * This function writes stringified @f into @buf. The function returns number
1169
 * of written chars. If final string is too large, the string will ends the with
1170
 * ' ...}' sequence and zero-terminator.
1171
 */
1172
uint
1173
flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f)
1174
{
1175
  return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1);
1176
}