Statistics
| Branch: | Revision:

iof-bird-daemon / lib / flowspec.c @ 62e64905

History | View | Annotate | Download (28.5 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 required to define",
263
  [FLOW_ST_CANNOT_USE_DONT_FRAGMENT]    = "Cannot use Don't fragment flag in IPv6 flow"
264
};
265

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

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

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

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

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

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

    
335
  if (fb->this_type == FLOW_TYPE_FRAGMENT && fb->ipv6 && (mask & 0x01))
336
    cf_error("Invalid mask 0x%x. Bit 0 must be 0", mask);
337

    
338
  if (val & ~mask)
339
    cf_error("Value 0x%x outside bitmask 0x%x", val, mask);
340
}
341

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

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

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

    
363
  if (max == 2 && (val > 0xffff))
364
    cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val);
365
}
366

    
367
static enum flow_validated_state
368
flow_validate(const byte *nlri, uint len, int ipv6)
369
{
370
  enum flow_type type = 0;
371
  const byte *pos = nlri;
372
  const byte *end = nlri + len;
373
  int met_dst_pfx = 0;
374

    
375
  while (pos < end)
376
  {
377
    /* Check increasing type ordering */
378
    if (*pos <= type)
379
      return FLOW_ST_BAD_TYPE_ORDER;
380
    type = *pos++;
381

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

    
393
      uint bytes = BYTES(pxlen);
394
      if (ipv6)
395
      {
396
        uint pxoffset = *pos++;
397
        if (pxoffset > IP6_MAX_PREFIX_LENGTH || pxoffset > pxlen)
398
          return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
399
        bytes -= pxoffset / 8;
400
      }
401
      pos += bytes;
402

    
403
      break;
404
    }
405

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

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

    
435
        last = isset_end(pos);
436

    
437
        /* The AND bit should in the first operator byte of a sequence */
438
        if (first && isset_and(pos))
439
          return FLOW_ST_AND_BIT_SHOULD_BE_UNSET;
440

    
441
        /* This bit should be zero */
442
        if (*pos & 0x08)
443
          return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
444

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

    
459
        /* Bit-7 must be 0 [draft-ietf-idr-flow-spec-v6] */
460
        if (ipv6 && type == FLOW_TYPE_FRAGMENT && (*(pos+1) & 0x01))
461
          return FLOW_ST_CANNOT_USE_DONT_FRAGMENT;
462
        /* XXX: Could be a fragment component encoded in 2-bytes? */
463

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

    
470
        if (pos > end && !last)
471
          return FLOW_ST_NOT_COMPLETE;
472

    
473
        if (pos > (end+1))
474
          return FLOW_ST_NOT_COMPLETE;
475

    
476
        first = 0;
477
      }
478
      break;
479
    }
480
    default:
481
      return FLOW_ST_UNKNOWN_COMPONENT;
482
    }
483
  }
484

    
485
  if (pos != end)
486
    return FLOW_ST_NOT_COMPLETE;
487

    
488
  if (!ipv6 && !met_dst_pfx)
489
    return FLOW_ST_DEST_PREFIX_REQUIRED;
490

    
491
  return FLOW_ST_VALID;
492
}
493

    
494
/**
495
 * flow4_validate - check untrustworthy IPv4 flowspec data stream
496
 * @nlri: flowspec data stream without compressed encoded length value
497
 * @len: length of @nlri
498
 *
499
 * This function checks meaningfulness of binary flowspec. It should return
500
 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
501
 * returns some other %FLOW_ST_xxx state.
502
 */
503
inline enum flow_validated_state
504
flow4_validate(const byte *nlri, uint len)
505
{
506
  return flow_validate(nlri, len, 0);
507
}
508

    
509
/**
510
 * flow6_validate - check untrustworthy IPv6 flowspec data stream
511
 * @nlri: flowspec binary stream without encoded length value
512
 * @len: length of @nlri
513
 *
514
 * This function checks meaningfulness of binary flowspec. It should return
515
 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
516
 * returns some other %FLOW_ST_xxx state.
517
 */
518
inline enum flow_validated_state
519
flow6_validate(const byte *nlri, uint len)
520
{
521
  return flow_validate(nlri, len, 1);
522
}
523

    
524
/**
525
 * flow4_validate_cf - validate flowspec data structure &net_addr_flow4 in parsing time
526
 * @f: flowspec data structure &net_addr_flow4
527
 *
528
 * Check if @f is valid flowspec data structure. Can call cf_error() function
529
 * with a textual description of reason to failing of validation.
530
 */
531
void
532
flow4_validate_cf(net_addr_flow4 *f)
533
{
534
  enum flow_validated_state r = flow4_validate(flow4_first_part(f), flow_read_length(f->data));
535

    
536
  if (r != FLOW_ST_VALID)
537
    cf_error("Invalid flow route: %s", flow_validated_state_str(r));
538
}
539

    
540
/**
541
 * flow6_validate_cf - validate flowspec data structure &net_addr_flow6 in parsing time
542
 * @f: flowspec data structure &net_addr_flow6
543
 *
544
 * Check if @f is valid flowspec data structure. Can call cf_error() function
545
 * with a textual description of reason to failing of validation.
546
 */
547
void
548
flow6_validate_cf(net_addr_flow6 *f)
549
{
550
  enum flow_validated_state r = flow6_validate(flow6_first_part(f), flow_read_length(f->data));
551

    
552
  if (r != FLOW_ST_VALID)
553
    cf_error("Invalid flow route: %s", flow_validated_state_str(r));
554
}
555

    
556

    
557
/*
558
 *         Flowspec Builder
559
 */
560

    
561
/**
562
 * flow_builder_init - constructor for flowspec builder instance
563
 * @pool: memory pool
564
 *
565
 * This function prepares flowspec builder instance using memory pool @pool.
566
 */
567
struct flow_builder *
568
flow_builder_init(pool *pool)
569
{
570
  struct flow_builder *fb = mb_allocz(pool, sizeof(struct flow_builder));
571
  BUFFER_INIT(fb->data, pool, 4);
572
  return fb;
573
}
574

    
575
static int
576
is_stackable_type(enum flow_type type)
577
{
578
  switch (type)
579
  {
580
  case FLOW_TYPE_IP_PROTOCOL:
581
  case FLOW_TYPE_PORT:
582
  case FLOW_TYPE_DST_PORT:
583
  case FLOW_TYPE_SRC_PORT:
584
  case FLOW_TYPE_ICMP_TYPE:
585
  case FLOW_TYPE_ICMP_CODE:
586
  case FLOW_TYPE_TCP_FLAGS:
587
  case FLOW_TYPE_PACKET_LENGTH:
588
  case FLOW_TYPE_DSCP:
589
  case FLOW_TYPE_FRAGMENT:
590
  case FLOW_TYPE_LABEL:
591
    return 1;
592

    
593
  default:
594
    /* The unknown components are not stack-able in default */
595
    return 0;
596
  }
597
}
598

    
599
static int
600
builder_add_prepare(struct flow_builder *fb)
601
{
602
  if (fb->parts[fb->this_type].length)
603
  {
604
    if (fb->last_type != fb->this_type)
605
      return 0;
606

    
607
    if (!is_stackable_type(fb->this_type))
608
      return 0;
609
  }
610
  else
611
  {
612
    fb->parts[fb->this_type].offset = fb->data.used;
613
  }
614

    
615
  return 1;
616
}
617

    
618
static void
619
builder_add_finish(struct flow_builder *fb)
620
{
621
  fb->parts[fb->this_type].length = fb->data.used - fb->parts[fb->this_type].offset;
622
  flow_builder_set_type(fb, fb->this_type);
623
}
624

    
625
static void
626
push_pfx_to_buffer(struct flow_builder *fb, u8 pxlen_bytes, byte *ip)
627
{
628
  for (int i = 0; i < pxlen_bytes; i++)
629
    BUFFER_PUSH(fb->data) = *ip++;
630
}
631

    
632
/**
633
 * flow_builder4_add_pfx - add IPv4 prefix
634
 * @fb: flowspec builder instance
635
 * @n4: net address of type IPv4
636
 *
637
 * This function add IPv4 prefix into flowspec builder instance.
638
 */
639
int
640
flow_builder4_add_pfx(struct flow_builder *fb, const net_addr_ip4 *n4)
641
{
642
  if (!builder_add_prepare(fb))
643
    return 0;
644

    
645
  ip4_addr ip4 = ip4_hton(n4->prefix);
646

    
647
  BUFFER_PUSH(fb->data) = fb->this_type;
648
  BUFFER_PUSH(fb->data) = n4->pxlen;
649
  push_pfx_to_buffer(fb, BYTES(n4->pxlen), (byte *) &ip4);
650

    
651
  builder_add_finish(fb);
652
  return 1;
653
}
654

    
655
/**
656
 * flow_builder6_add_pfx - add IPv6 prefix
657
 * @fb: flowspec builder instance
658
 * @n6: net address of type IPv4
659
 * @pxoffset: prefix offset for @n6
660
 *
661
 * This function add IPv4 prefix into flowspec builder instance. This function
662
 * should return 1 for successful adding, otherwise returns %0.
663
 */
664
int
665
flow_builder6_add_pfx(struct flow_builder *fb, const net_addr_ip6 *n6, u32 pxoffset)
666
{
667
  if (!builder_add_prepare(fb))
668
    return 0;
669

    
670
  ip6_addr ip6 = ip6_hton(n6->prefix);
671

    
672
  BUFFER_PUSH(fb->data) = fb->this_type;
673
  BUFFER_PUSH(fb->data) = n6->pxlen;
674
  BUFFER_PUSH(fb->data) = pxoffset;
675
  push_pfx_to_buffer(fb, BYTES(n6->pxlen) - (pxoffset / 8), ((byte *) &ip6) + (pxoffset / 8));
676

    
677
  builder_add_finish(fb);
678
  return 1;
679
}
680

    
681
/**
682
 * flow_builder_add_op_val - add operator/value pair
683
 * @fb: flowspec builder instance
684
 * @op: operator
685
 * @value: value
686
 *
687
 * This function add operator/value pair as a part of a flowspec component. It
688
 * is required to set appropriate flowspec component type using function
689
 * flow_builder_set_type(). This function should return 1 for successful
690
 * adding, otherwise returns 0.
691
 */
692
int
693
flow_builder_add_op_val(struct flow_builder *fb, byte op, u32 value)
694
{
695
  if (!builder_add_prepare(fb))
696
    return 0;
697

    
698
  if (fb->this_type == fb->last_type)
699
  {
700
    /* Remove the end-bit from last operand-value pair of the component */
701
    fb->data.data[fb->last_op_offset] &= 0x7f;
702
  }
703
  else
704
  {
705
    BUFFER_PUSH(fb->data) = fb->this_type;
706
  }
707

    
708
  fb->last_op_offset = fb->data.used;
709

    
710
  /* Set the end-bit for operand-value pair of the component */
711
  op |= 0x80;
712

    
713
  if (value & 0xff00)
714
  {
715
    BUFFER_PUSH(fb->data) = op | 0x10;
716
    put_u16(BUFFER_INC(fb->data, 2), value);
717
  }
718
  else
719
  {
720
    BUFFER_PUSH(fb->data) = op;
721
    BUFFER_PUSH(fb->data) = (u8) value;
722
  }
723

    
724
  builder_add_finish(fb);
725
  return 1;
726
}
727

    
728
/**
729
 * flow_builder_add_val_mask - add value/bitmask pair
730
 * @fb: flowspec builder instance
731
 * @op: operator
732
 * @value: value
733
 * @mask: bitmask
734
 *
735
 * It is required to set appropriate flowspec component type using function
736
 * flow_builder_set_type(). This function should return 1 for successful adding,
737
 * otherwise returns 0.
738
 */
739
int
740
flow_builder_add_val_mask(struct flow_builder *fb, byte op, u32 value, u32 mask)
741
{
742
  u32 a =  value & mask;
743
  u32 b = ~value & mask;
744

    
745
  if (a)
746
  {
747
    flow_builder_add_op_val(fb, op ^ 0x01, a);
748
    op |= 0x40;
749
  }
750

    
751
  if (b)
752
    flow_builder_add_op_val(fb, op ^ 0x02, b);
753

    
754
  return 1;
755
}
756

    
757

    
758
/**
759
 * flow_builder_set_type - set type of next flowspec component
760
 * @fb: flowspec builder instance
761
 * @type: flowspec component type
762
 *
763
 * This function sets type of next flowspec component. It is necessary to call
764
 * this function before each changing of adding flowspec component.
765
 */
766
void
767
flow_builder_set_type(struct flow_builder *fb, enum flow_type type)
768
{
769
  fb->last_type = fb->this_type;
770
  fb->this_type = type;
771
}
772

    
773
static ip4_addr
774
flow_read_ip4(const byte *px, uint pxlen)
775
{
776
  ip4_addr ip = IP4_NONE;
777
  memcpy(&ip, px, BYTES(pxlen));
778
  return ip4_ntoh(ip);
779
}
780

    
781
static ip6_addr
782
flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
783
{
784
  uint floor_offset = BYTES(pxoffset - (pxoffset % 8));
785
  uint ceil_len = BYTES(pxlen);
786
  ip6_addr ip = IP6_NONE;
787

    
788
  memcpy(((byte *) &ip) + floor_offset, px, ceil_len - floor_offset);
789

    
790
  return ip6_ntoh(ip);
791
}
792

    
793
static void
794
builder_write_parts(struct flow_builder *fb, byte *buf)
795
{
796
  for (int i = 1; i < FLOW_TYPE_MAX; i++)
797
  {
798
    if (fb->parts[i].length)
799
    {
800
      memcpy(buf, fb->data.data + fb->parts[i].offset, fb->parts[i].length);
801
      buf += fb->parts[i].length;
802
    }
803
  }
804
}
805

    
806
/**
807
 * flow_builder4_finalize - assemble final flowspec data structure &net_addr_flow4
808
 * @fb: flowspec builder instance
809
 * @lpool: linear memory pool
810
 *
811
 * This function returns final flowspec data structure &net_addr_flow4 allocated
812
 * onto @lpool linear memory pool.
813
 */
814
net_addr_flow4 *
815
flow_builder4_finalize(struct flow_builder *fb, linpool *lpool)
816
{
817
  uint data_len = fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
818
  net_addr_flow4 *f = lp_alloc(lpool, sizeof(struct net_addr_flow4) + data_len);
819

    
820
  ip4_addr prefix = IP4_NONE;
821
  uint pxlen = 0;
822

    
823
  if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
824
  {
825
    byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
826
    pxlen = *p++;
827
    prefix = flow_read_ip4(p, pxlen);
828
  }
829
  *f = NET_ADDR_FLOW4(prefix, pxlen, data_len);
830

    
831
  builder_write_parts(fb, f->data + flow_write_length(f->data, fb->data.used));
832

    
833
  return f;
834
}
835

    
836
/**
837
 * flow_builder6_finalize - assemble final flowspec data structure &net_addr_flow6
838
 * @fb: flowspec builder instance
839
 * @lpool: linear memory pool for allocation of
840
 *
841
 * This function returns final flowspec data structure &net_addr_flow6 allocated
842
 * onto @lpool linear memory pool.
843
 */
844
net_addr_flow6 *
845
flow_builder6_finalize(struct flow_builder *fb, linpool *lpool)
846
{
847
  uint data_len =  fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
848
  net_addr_flow6 *n = lp_alloc(lpool, sizeof(net_addr_flow6) + data_len);
849

    
850
  ip6_addr prefix = IP6_NONE;
851
  uint pxlen = 0;
852

    
853
  if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
854
  {
855
    byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
856
    pxlen = *p++;
857
    uint pxoffset = *p++;
858
    prefix = flow_read_ip6(p, pxlen, pxoffset);
859
  }
860
  *n = NET_ADDR_FLOW6(prefix, pxlen, data_len);
861

    
862
  builder_write_parts(fb, n->data + flow_write_length(n->data, fb->data.used));
863

    
864
  return n;
865
}
866

    
867
/**
868
 * flow_builder_clear - flush flowspec builder instance for another flowspec creation
869
 * @fb: flowspec builder instance
870
 *
871
 * This function flushes all data from builder but it maintains pre-allocated
872
 * buffer space.
873
 */
874
void
875
flow_builder_clear(struct flow_builder *fb)
876
{
877
  BUFFER(byte) data;
878
  BUFFER_FLUSH(fb->data);
879

    
880
  BUFFER_SHALLOW_COPY(data, fb->data);
881
  memset(fb, 0, sizeof(struct flow_builder));
882
  BUFFER_SHALLOW_COPY(fb->data, data);
883
}
884

    
885

    
886
/*
887
 *         Net Formatting
888
 */
889

    
890
/* Flowspec operators for [op, value]+ pairs */
891
#define FLOW_TRUE        0b000
892
#define FLOW_EQ                0b001
893
#define FLOW_GT                0b010
894
#define FLOW_GTE        0b011
895
#define FLOW_LT                0b100
896
#define FLOW_LTE        0b101
897
#define FLOW_NEQ        0b110
898
#define FLOW_FALSE        0b111
899

    
900
static const char *
901
num_op_str(const byte *op)
902
{
903
  switch (*op & 0x07)
904
  {
905
  case FLOW_TRUE:         return "true";
906
  case FLOW_EQ:         return "=";
907
  case FLOW_GT:         return ">";
908
  case FLOW_GTE:         return ">=";
909
  case FLOW_LT:         return "<";
910
  case FLOW_LTE:         return "<=";
911
  case FLOW_NEQ:         return "!=";
912
  case FLOW_FALSE:         return "false";
913
  }
914

    
915
  return NULL;
916
}
917

    
918
static u64
919
get_value(const byte *val, u8 len)
920
{
921
  switch (len)
922
  {
923
  case 1: return *val;
924
  case 2: return get_u16(val);
925
  case 4: return get_u32(val);
926
  case 8: return get_u64(val);
927
  }
928

    
929
  return 0;
930
}
931

    
932
static int
933
is_bitmask(enum flow_type type)
934
{
935
  switch (type)
936
  {
937
  case FLOW_TYPE_TCP_FLAGS:
938
  case FLOW_TYPE_FRAGMENT:
939
  case FLOW_TYPE_LABEL:
940
    return 1;
941

    
942
  default:
943
    return 0;
944
  }
945
}
946

    
947
static const char *
948
fragment_val_str(u8 val)
949
{
950
  switch (val)
951
  {
952
  case 1: return "dont_fragment";
953
  case 2: return "is_fragment";
954
  case 4: return "first_fragment";
955
  case 8: return "last_fragment";
956
  }
957
  return "???";
958
}
959

    
960
static int
961
net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
962
{
963
  buffer b = {
964
    .start = buf,
965
    .pos = buf,
966
    .end = buf + blen,
967
  };
968

    
969
  const byte *part = flow_first_part(data);
970
  *buf = 0;
971

    
972
  if (ipv6)
973
    buffer_puts(&b, "flow6 { ");
974
  else
975
    buffer_puts(&b, "flow4 { ");
976

    
977
  while (part)
978
  {
979
    buffer_print(&b, "%s ", flow_type_str(*part, ipv6));
980

    
981
    switch (*part)
982
    {
983
    case FLOW_TYPE_DST_PREFIX:
984
    case FLOW_TYPE_SRC_PREFIX:
985
    {
986
      uint pxlen = *(part+1);
987
      if (ipv6)
988
      {
989
        uint pxoffset = *(part+2);
990
        if (pxoffset)
991
          buffer_print(&b, "%I6/%u offset %u; ", flow_read_ip6(part+3,pxlen,pxoffset), pxlen, pxoffset);
992
        else
993
          buffer_print(&b, "%I6/%u; ", flow_read_ip6(part+3,pxlen,0), pxlen);
994
      }
995
      else
996
      {
997
        buffer_print(&b, "%I4/%u; ", flow_read_ip4(part+2,pxlen), pxlen);
998
      }
999
      break;
1000
    }
1001

    
1002
    case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
1003
    case FLOW_TYPE_PORT:
1004
    case FLOW_TYPE_DST_PORT:
1005
    case FLOW_TYPE_SRC_PORT:
1006
    case FLOW_TYPE_ICMP_TYPE:
1007
    case FLOW_TYPE_ICMP_CODE:
1008
    case FLOW_TYPE_TCP_FLAGS:
1009
    case FLOW_TYPE_PACKET_LENGTH:
1010
    case FLOW_TYPE_DSCP:
1011
    case FLOW_TYPE_FRAGMENT:
1012
    case FLOW_TYPE_LABEL:
1013
    {
1014
      const byte *last_op = NULL;
1015
      const byte *op = part+1;
1016
      u64 val;
1017
      uint len;
1018
      uint first = 1;
1019

    
1020
      while (1)
1021
      {
1022
        if (!first)
1023
        {
1024
          /* XXX: I don't like this so complicated if-tree */
1025
          if (!isset_and(op) && !is_bitmask(*part) &&
1026
              ((num_op(     op) == FLOW_EQ) || (num_op(     op) == FLOW_GTE)) &&
1027
              ((num_op(last_op) == FLOW_EQ) || (num_op(last_op) == FLOW_LTE)))
1028
          {
1029
            b.pos--; /* Remove last char (it is a space) */
1030
            buffer_puts(&b, ",");
1031
          }
1032
          else if (isset_and(op) && is_bitmask(*part))
1033
          {
1034
            b.pos--; /* Remove last char (it is a space) */
1035
            buffer_puts(&b, ",");
1036
          }
1037
          else
1038
          {
1039
            buffer_puts(&b, isset_and(op) ? "&& " : "|| ");
1040
          }
1041
        }
1042
        first = 0;
1043

    
1044
        len = get_value_length(op);
1045
        val = get_value(op+1, len);
1046

    
1047
        if (is_bitmask(*part))
1048
        {
1049
          /*
1050
           *   Not Match  Show
1051
           *  ------------------
1052
           *    0    0    !0/B
1053
           *    0    1     B/B
1054
           *    1    0     0/B
1055
           *    1    1    !B/B
1056
           */
1057

    
1058
          if ((*op & 0x3) == 0x3 || (*op & 0x3) == 0)
1059
            buffer_puts(&b, "!");
1060

    
1061
          if (*part == FLOW_TYPE_FRAGMENT && (val == 1 || val == 2 || val == 4 || val == 8))
1062
            buffer_print(&b, "%s%s", ((*op & 0x1) ? "" : "!"), fragment_val_str(val));
1063
          else
1064
            buffer_print(&b, "0x%x/0x%x", ((*op & 0x1) ? val : 0), val);
1065
        }
1066
        else
1067
        {
1068
          if (!isset_end(op) && !isset_and(op) && isset_and(op+1+len) &&
1069
              (num_op(op) == FLOW_GTE) && (num_op(op+1+len) == FLOW_LTE))
1070
          {
1071
            /* Display interval */
1072
            buffer_print(&b, "%u..", val);
1073
            op += 1 + len;
1074
            len = get_value_length(op);
1075
            val = get_value(op+1, len);
1076
            buffer_print(&b, "%u", val);
1077
          }
1078
          else if (num_op(op) == FLOW_EQ)
1079
          {
1080
            buffer_print(&b, "%u", val);
1081
          }
1082
          else
1083
          {
1084
            buffer_print(&b, "%s %u", num_op_str(op), val);
1085
          }
1086
        }
1087

    
1088
        if (isset_end(op))
1089
        {
1090
          buffer_puts(&b, "; ");
1091
          break;
1092
        }
1093
        else
1094
        {
1095
          buffer_puts(&b, " ");
1096
        }
1097

    
1098
        last_op = op;
1099
        op += 1 + len;
1100
      }
1101
    }
1102
    }
1103

    
1104
    part = flow_next_part(part, data+dlen, ipv6);
1105
  }
1106

    
1107
  buffer_puts(&b, "}");
1108

    
1109
  if (b.pos == b.end)
1110
  {
1111
    b.pos = b.start + MIN(blen - 6, strlen(b.start));
1112
    buffer_puts(&b, " ...}");
1113
  }
1114

    
1115
  return b.pos - b.start;
1116
}
1117

    
1118
/**
1119
 * flow4_net_format - stringify flowspec data structure &net_addr_flow4
1120
 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1121
 * @blen: free allocated space in @buf
1122
 * @f: flowspec data structure &net_addr_flow4 for stringify
1123
 *
1124
 * This function writes stringified @f into @buf. The function returns number
1125
 * of written chars. If final string is too large, the string will ends the with
1126
 * ' ...}' sequence and zero-terminator.
1127
 */
1128
int
1129
flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f)
1130
{
1131
  return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow4), 0);
1132
}
1133

    
1134
/**
1135
 * flow6_net_format - stringify flowspec data structure &net_addr_flow6
1136
 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1137
 * @blen: free allocated space in @buf
1138
 * @f: flowspec data structure &net_addr_flow4 for stringify
1139
 *
1140
 * This function writes stringified @f into @buf. The function returns number
1141
 * of written chars. If final string is too large, the string will ends the with
1142
 * ' ...}' sequence and zero-terminator.
1143
 */
1144
int
1145
flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f)
1146
{
1147
  return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1);
1148
}