Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/selectors/traffic_selector.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2007-2017 Tobias Brunner
3
 * Copyright (C) 2005-2007 Martin Willi
4
 * Copyright (C) 2005 Jan Hutter
5
 *
6
 * Copyright (C) secunet Security Networks AG
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU General Public License as published by the
10
 * Free Software Foundation; either version 2 of the License, or (at your
11
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
12
 *
13
 * This program is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16
 * for more details.
17
 */
18
19
#include <string.h>
20
#include <stdio.h>
21
22
#include "traffic_selector.h"
23
24
#include <utils/debug.h>
25
#include <utils/utils.h>
26
#include <utils/identification.h>
27
#include <collections/linked_list.h>
28
29
0
#define IPV4_LEN  4
30
0
#define IPV6_LEN  16
31
0
#define TS_IP_LEN(this) ({ ((this)->type == TS_IPV4_ADDR_RANGE) ? IPV4_LEN : IPV6_LEN; })
32
33
0
#define NON_SUBNET_ADDRESS_RANGE  255
34
35
ENUM_BEGIN(ts_type_name, TS_IPV4_ADDR_RANGE, TS_IPV6_ADDR_RANGE,
36
  "TS_IPV4_ADDR_RANGE",
37
  "TS_IPV6_ADDR_RANGE");
38
ENUM_NEXT(ts_type_name, TS_SECLABEL, TS_SECLABEL, TS_IPV6_ADDR_RANGE,
39
  "TS_SECLABEL");
40
ENUM_END(ts_type_name, TS_SECLABEL);
41
42
typedef struct private_traffic_selector_t private_traffic_selector_t;
43
44
/**
45
 * Private data of an traffic_selector_t object
46
 */
47
struct private_traffic_selector_t {
48
49
  /**
50
   * Public part
51
   */
52
  traffic_selector_t public;
53
54
  /**
55
   * Type of address
56
   */
57
  ts_type_t type;
58
59
  /**
60
   * IP protocol (UDP, TCP, ICMP, ...)
61
   */
62
  uint8_t protocol;
63
64
  /**
65
   * narrow this traffic selector to hosts external ip
66
   * if set, from and to have no meaning until set_address() is called
67
   */
68
  bool dynamic;
69
70
  /**
71
   * subnet size in CIDR notation, 255 means a non-subnet address range
72
   */
73
  uint8_t netbits;
74
75
  /**
76
   * begin of address range, network order
77
   */
78
  char from[IPV6_LEN];
79
80
  /**
81
   * end of address range, network order
82
   */
83
  char to[IPV6_LEN];
84
85
  /**
86
   * begin of port range
87
   */
88
  uint16_t from_port;
89
90
  /**
91
   * end of port range
92
   */
93
  uint16_t to_port;
94
};
95
96
/**
97
 * calculate the "to"-address for the "from" address and a subnet size
98
 */
99
static void calc_range(private_traffic_selector_t *this, uint8_t netbits)
100
0
{
101
0
  size_t len;
102
0
  int bytes, bits;
103
0
  uint8_t mask;
104
105
0
  this->netbits = netbits;
106
107
0
  len   = TS_IP_LEN(this);
108
0
  bytes = (netbits + 7)/8;
109
0
  bits  = (bytes * 8) - netbits;
110
0
  mask  = bits ? (1 << bits) - 1 : 0;
111
112
0
  memcpy(this->to, this->from, bytes);
113
0
  memset(this->from + bytes, 0x00, len - bytes);
114
0
  memset(this->to   + bytes, 0xff, len - bytes);
115
116
0
  if (bytes)
117
0
  {
118
0
    this->from[bytes-1] &= ~mask;
119
0
    this->to[bytes-1]   |=  mask;
120
0
  }
121
0
}
122
123
/**
124
 * calculate the subnet size from the "to" and "from" addresses
125
 */
126
static uint8_t calc_netbits(private_traffic_selector_t *this)
127
0
{
128
0
  int byte, bit;
129
0
  uint8_t netbits;
130
0
  size_t size = TS_IP_LEN(this);
131
0
  bool prefix = TRUE;
132
133
  /* a perfect match results in a single address with a /32 or /128 netmask */
134
0
  netbits = (size * 8);
135
0
  this->netbits = netbits;
136
137
  /* go through all bits of the addresses, beginning in the front.
138
   * as long as they are equal, the subnet gets larger
139
   */
140
0
  for (byte = 0; byte < size; byte++)
141
0
  {
142
0
    for (bit = 7; bit >= 0; bit--)
143
0
    {
144
0
      uint8_t bitmask = 1 << bit;
145
146
0
      if (prefix)
147
0
      {
148
0
        if ((bitmask & this->from[byte]) != (bitmask & this->to[byte]))
149
0
        {
150
          /* store the common prefix which might be a true subnet */
151
0
          netbits = (7 - bit) + (byte * 8);
152
0
          this->netbits = netbits;
153
0
          prefix = FALSE;
154
0
        }
155
0
      }
156
0
      else
157
0
      {
158
0
        if ((bitmask & this->from[byte]) || !(bitmask & this->to[byte]))
159
0
        {
160
0
          this->netbits = NON_SUBNET_ADDRESS_RANGE;
161
0
          return netbits;  /* return a pseudo subnet */
162
163
0
        }
164
0
      }
165
0
    }
166
0
  }
167
0
  return netbits;  /* return a true subnet */
168
0
}
169
170
/**
171
 * internal generic constructor
172
 */
173
static private_traffic_selector_t *traffic_selector_create(uint8_t protocol,
174
            ts_type_t type, uint16_t from_port, uint16_t to_port);
175
176
/**
177
 * Check if TS contains "opaque" ports
178
 */
179
static bool is_opaque(private_traffic_selector_t *this)
180
0
{
181
0
  return this->from_port == 0xffff && this->to_port == 0;
182
0
}
183
184
/**
185
 * Check if TS contains "any" ports
186
 */
187
static bool is_any(private_traffic_selector_t *this)
188
0
{
189
0
  return this->from_port == 0 && this->to_port == 0xffff;
190
0
}
191
192
/**
193
 * Print ICMP/ICMPv6 type and code
194
 */
195
static int print_icmp(printf_hook_data_t *data, uint16_t port)
196
0
{
197
0
  uint8_t type, code;
198
199
0
  type = traffic_selector_icmp_type(port);
200
0
  code = traffic_selector_icmp_code(port);
201
0
  if (code)
202
0
  {
203
0
    return print_in_hook(data, "%d(%d)", type, code);
204
0
  }
205
0
  return print_in_hook(data, "%d", type);
206
0
}
207
208
/**
209
 * Described in header.
210
 */
211
int traffic_selector_printf_hook(printf_hook_data_t *data,
212
              printf_hook_spec_t *spec, const void *const *args)
213
0
{
214
0
  private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0]));
215
0
  linked_list_t *list = *((linked_list_t**)(args[0]));
216
0
  enumerator_t *enumerator;
217
0
  char from_str[INET6_ADDRSTRLEN] = "";
218
0
  char to_str[INET6_ADDRSTRLEN] = "";
219
0
  char *serv_proto = NULL, *sep = "";
220
0
  bool has_proto, has_ports;
221
0
  size_t written = 0, len;
222
0
  char from[IPV6_LEN], to[IPV6_LEN];
223
224
0
  if (this == NULL)
225
0
  {
226
0
    return print_in_hook(data, "(null)");
227
0
  }
228
229
0
  if (spec->hash)
230
0
  {
231
0
    enumerator = list->create_enumerator(list);
232
0
    while (enumerator->enumerate(enumerator, (void**)&this))
233
0
    {
234
0
      written += print_in_hook(data, "%s%R", sep, this);
235
0
      sep = " ";
236
0
    }
237
0
    enumerator->destroy(enumerator);
238
0
    return written;
239
0
  }
240
241
0
  len = TS_IP_LEN(this);
242
0
  memset(from, 0, len);
243
0
  memset(to, 0xFF, len);
244
0
  if (this->dynamic &&
245
0
    memeq(this->from, from, len) && memeq(this->to, to, len))
246
0
  {
247
0
    written += print_in_hook(data, "dynamic");
248
0
  }
249
0
  else
250
0
  {
251
0
    if (this->type == TS_IPV4_ADDR_RANGE)
252
0
    {
253
0
      inet_ntop(AF_INET, &this->from, from_str, sizeof(from_str));
254
0
    }
255
0
    else
256
0
    {
257
0
      inet_ntop(AF_INET6, &this->from, from_str, sizeof(from_str));
258
0
    }
259
0
    if (this->netbits == NON_SUBNET_ADDRESS_RANGE)
260
0
    {
261
0
      if (this->type == TS_IPV4_ADDR_RANGE)
262
0
      {
263
0
        inet_ntop(AF_INET, &this->to, to_str, sizeof(to_str));
264
0
      }
265
0
      else
266
0
      {
267
0
        inet_ntop(AF_INET6, &this->to, to_str, sizeof(to_str));
268
0
      }
269
0
      written += print_in_hook(data, "%s..%s", from_str, to_str);
270
0
    }
271
0
    else
272
0
    {
273
0
      written += print_in_hook(data, "%s/%d", from_str, this->netbits);
274
0
    }
275
0
  }
276
277
  /* check if we have protocol and/or port selectors */
278
0
  has_proto = this->protocol != 0;
279
0
  has_ports = !is_any(this);
280
281
0
  if (!has_proto && !has_ports)
282
0
  {
283
0
    return written;
284
0
  }
285
286
0
  written += print_in_hook(data, "[");
287
288
  /* build protocol string */
289
0
  if (has_proto)
290
0
  {
291
0
    struct protoent *proto = getprotobynumber(this->protocol);
292
293
0
    if (proto)
294
0
    {
295
0
      written += print_in_hook(data, "%s", proto->p_name);
296
0
      serv_proto = proto->p_name;
297
0
    }
298
0
    else
299
0
    {
300
0
      written += print_in_hook(data, "%d", this->protocol);
301
0
    }
302
0
  }
303
0
  else
304
0
  {
305
0
    written += print_in_hook(data, "0");
306
0
  }
307
308
  /* build port string */
309
0
  if (has_ports)
310
0
  {
311
0
    written += print_in_hook(data, "/");
312
313
0
    if (this->from_port == this->to_port)
314
0
    {
315
0
      struct servent *serv;
316
317
0
      if (this->protocol == IPPROTO_ICMP ||
318
0
        this->protocol == IPPROTO_ICMPV6)
319
0
      {
320
0
        written += print_icmp(data, this->from_port);
321
0
      }
322
0
      else
323
0
      {
324
0
        serv = getservbyport(htons(this->from_port), serv_proto);
325
0
        if (serv)
326
0
        {
327
0
          written += print_in_hook(data, "%s", serv->s_name);
328
0
        }
329
0
        else
330
0
        {
331
0
          written += print_in_hook(data, "%d", this->from_port);
332
0
        }
333
0
      }
334
0
    }
335
0
    else if (is_opaque(this))
336
0
    {
337
0
      written += print_in_hook(data, "OPAQUE");
338
0
    }
339
0
    else if (this->protocol == IPPROTO_ICMP ||
340
0
         this->protocol == IPPROTO_ICMPV6)
341
0
    {
342
0
      written += print_icmp(data, this->from_port);
343
0
      written += print_in_hook(data, "-");
344
0
      written += print_icmp(data, this->to_port);
345
0
    }
346
0
    else
347
0
    {
348
0
      written += print_in_hook(data, "%d-%d",
349
0
                   this->from_port, this->to_port);
350
0
    }
351
0
  }
352
353
0
  written += print_in_hook(data, "]");
354
355
0
  return written;
356
0
}
357
358
METHOD(traffic_selector_t, get_subset, traffic_selector_t*,
359
  private_traffic_selector_t *this, traffic_selector_t *other_public)
360
0
{
361
0
  private_traffic_selector_t *other, *subset;
362
0
  uint16_t from_port, to_port;
363
0
  u_char *from, *to;
364
0
  uint8_t protocol;
365
0
  size_t size;
366
367
0
  other = (private_traffic_selector_t*)other_public;
368
369
0
  if (this->dynamic || other->dynamic)
370
0
  { /* no set_address() applied, TS has no subset */
371
0
    return NULL;
372
0
  }
373
374
0
  if (this->type != other->type)
375
0
  {
376
0
    return NULL;
377
0
  }
378
379
0
  if (this->protocol != other->protocol &&
380
0
    this->protocol != 0 && other->protocol != 0)
381
0
  {
382
0
    return NULL;
383
0
  }
384
  /* select protocol, which is not zero */
385
0
  protocol = max(this->protocol, other->protocol);
386
387
0
  if ((is_opaque(this) && is_opaque(other)) ||
388
0
    (is_opaque(this) && is_any(other)) ||
389
0
    (is_opaque(other) && is_any(this)))
390
0
  {
391
0
    from_port = 0xffff;
392
0
    to_port = 0;
393
0
  }
394
0
  else
395
0
  {
396
    /* calculate the maximum port range allowed for both */
397
0
    from_port = max(this->from_port, other->from_port);
398
0
    to_port = min(this->to_port, other->to_port);
399
0
    if (from_port > to_port)
400
0
    {
401
0
      return NULL;
402
0
    }
403
0
  }
404
0
  size = TS_IP_LEN(this);
405
  /* get higher from-address */
406
0
  if (memcmp(this->from, other->from, size) > 0)
407
0
  {
408
0
    from = this->from;
409
0
  }
410
0
  else
411
0
  {
412
0
    from = other->from;
413
0
  }
414
  /* get lower to-address */
415
0
  if (memcmp(this->to, other->to, size) > 0)
416
0
  {
417
0
    to = other->to;
418
0
  }
419
0
  else
420
0
  {
421
0
    to = this->to;
422
0
  }
423
  /* if "from" > "to", we don't have a match */
424
0
  if (memcmp(from, to, size) > 0)
425
0
  {
426
0
    return NULL;
427
0
  }
428
429
  /* we have a match in protocol, port, and address: return it... */
430
0
  subset = traffic_selector_create(protocol, this->type, from_port, to_port);
431
0
  memcpy(subset->from, from, size);
432
0
  memcpy(subset->to, to, size);
433
0
  calc_netbits(subset);
434
435
0
  return &subset->public;
436
0
}
437
438
METHOD(traffic_selector_t, equals, bool,
439
  private_traffic_selector_t *this, traffic_selector_t *other)
440
0
{
441
0
  return traffic_selector_cmp(&this->public, other, NULL) == 0;
442
0
}
443
444
METHOD(traffic_selector_t, get_from_address, chunk_t,
445
  private_traffic_selector_t *this)
446
0
{
447
0
  return chunk_create(this->from, TS_IP_LEN(this));
448
0
}
449
450
METHOD(traffic_selector_t, get_to_address, chunk_t,
451
  private_traffic_selector_t *this)
452
0
{
453
0
  return chunk_create(this->to, TS_IP_LEN(this));
454
0
}
455
456
METHOD(traffic_selector_t, get_from_port, uint16_t,
457
  private_traffic_selector_t *this)
458
0
{
459
0
  return this->from_port;
460
0
}
461
462
METHOD(traffic_selector_t, get_to_port, uint16_t,
463
  private_traffic_selector_t *this)
464
0
{
465
0
  return this->to_port;
466
0
}
467
468
METHOD(traffic_selector_t, get_type, ts_type_t,
469
  private_traffic_selector_t *this)
470
0
{
471
0
  return this->type;
472
0
}
473
474
METHOD(traffic_selector_t, get_protocol, uint8_t,
475
  private_traffic_selector_t *this)
476
0
{
477
0
  return this->protocol;
478
0
}
479
480
METHOD(traffic_selector_t, is_host, bool,
481
  private_traffic_selector_t *this, host_t *host)
482
0
{
483
0
  if (host)
484
0
  {
485
0
    chunk_t addr;
486
0
    int family = host->get_family(host);
487
488
0
    if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
489
0
      (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
490
0
    {
491
0
      addr = host->get_address(host);
492
0
      if (memeq(addr.ptr, this->from, addr.len) &&
493
0
        memeq(addr.ptr, this->to, addr.len))
494
0
      {
495
0
        return TRUE;
496
0
      }
497
0
    }
498
0
  }
499
0
  else
500
0
  {
501
0
    size_t length = TS_IP_LEN(this);
502
503
0
    if (this->dynamic)
504
0
    {
505
0
      return TRUE;
506
0
    }
507
508
0
    if (memeq(this->from, this->to, length))
509
0
    {
510
0
      return TRUE;
511
0
    }
512
0
  }
513
0
  return FALSE;
514
0
}
515
516
METHOD(traffic_selector_t, is_dynamic, bool,
517
  private_traffic_selector_t *this)
518
0
{
519
0
  return this->dynamic;
520
0
}
521
522
METHOD(traffic_selector_t, set_address, void,
523
  private_traffic_selector_t *this, host_t *host)
524
0
{
525
0
  this->type = host->get_family(host) == AF_INET ? TS_IPV4_ADDR_RANGE
526
0
                           : TS_IPV6_ADDR_RANGE;
527
528
0
  if (host->is_anyaddr(host))
529
0
  {
530
0
    memset(this->from, 0x00, sizeof(this->from));
531
0
    memset(this->to, 0xFF, sizeof(this->to));
532
0
    this->netbits = 0;
533
0
  }
534
0
  else
535
0
  {
536
0
    chunk_t from = host->get_address(host);
537
0
    memcpy(this->from, from.ptr, from.len);
538
0
    memcpy(this->to, from.ptr, from.len);
539
0
    this->netbits = from.len * 8;
540
0
  }
541
0
  this->dynamic = FALSE;
542
0
}
543
544
METHOD(traffic_selector_t, is_contained_in, bool,
545
  private_traffic_selector_t *this, traffic_selector_t *other)
546
0
{
547
0
  private_traffic_selector_t *subset;
548
0
  bool contained_in = FALSE;
549
550
0
  subset = (private_traffic_selector_t*)get_subset(this, other);
551
552
0
  if (subset)
553
0
  {
554
0
    if (equals(subset, &this->public))
555
0
    {
556
0
      contained_in = TRUE;
557
0
    }
558
0
    free(subset);
559
0
  }
560
0
  return contained_in;
561
0
}
562
563
METHOD(traffic_selector_t, includes, bool,
564
  private_traffic_selector_t *this, host_t *host)
565
0
{
566
0
  chunk_t addr;
567
0
  int family = host->get_family(host);
568
569
0
  if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
570
0
    (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
571
0
  {
572
0
    addr = host->get_address(host);
573
574
0
    return memcmp(this->from, addr.ptr, addr.len) <= 0 &&
575
0
        memcmp(this->to, addr.ptr, addr.len) >= 0;
576
0
  }
577
578
0
  return FALSE;
579
0
}
580
581
METHOD(traffic_selector_t, to_subnet, bool,
582
  private_traffic_selector_t *this, host_t **net, uint8_t *mask)
583
0
{
584
  /* there is no way to do this cleanly, as the address range may
585
   * be anything else but a subnet. We use from_addr as subnet
586
   * and try to calculate a usable subnet mask.
587
   */
588
0
  int family, non_zero_bytes;
589
0
  uint16_t port = 0;
590
0
  chunk_t net_chunk;
591
592
0
  *mask = (this->netbits == NON_SUBNET_ADDRESS_RANGE) ? calc_netbits(this)
593
0
                            : this->netbits;
594
595
0
  switch (this->type)
596
0
  {
597
0
    case TS_IPV4_ADDR_RANGE:
598
0
      family = AF_INET;
599
0
      net_chunk.len = IPV4_LEN;
600
0
      break;
601
0
    case TS_IPV6_ADDR_RANGE:
602
0
      family = AF_INET6;
603
0
      net_chunk.len = IPV6_LEN;
604
0
      break;
605
0
    default:
606
      /* unreachable */
607
0
      return FALSE;
608
0
  }
609
610
0
  net_chunk.ptr = malloc(net_chunk.len);
611
0
  memset(net_chunk.ptr, 0x00, net_chunk.len);
612
0
  if (*mask)
613
0
  {
614
0
    non_zero_bytes = (*mask + 7) / 8;
615
0
    memcpy(net_chunk.ptr, this->from, non_zero_bytes);
616
0
    net_chunk.ptr[non_zero_bytes-1] &= 0xFF << (8 * non_zero_bytes - *mask);
617
0
  }
618
619
0
  if (this->to_port == this->from_port)
620
0
  {
621
0
    port = this->to_port;
622
0
  }
623
624
0
  *net = host_create_from_chunk(family, net_chunk, port);
625
0
  chunk_free(&net_chunk);
626
627
0
  return this->netbits != NON_SUBNET_ADDRESS_RANGE;
628
0
}
629
630
METHOD(traffic_selector_t, clone_, traffic_selector_t*,
631
  private_traffic_selector_t *this)
632
0
{
633
0
  private_traffic_selector_t *clone;
634
0
  size_t len = TS_IP_LEN(this);
635
636
0
  clone = traffic_selector_create(this->protocol, this->type,
637
0
                  this->from_port, this->to_port);
638
0
  clone->netbits = this->netbits;
639
0
  clone->dynamic = this->dynamic;
640
641
0
  memcpy(clone->from, this->from, len);
642
0
  memcpy(clone->to, this->to, len);
643
0
  return &clone->public;
644
0
}
645
646
METHOD(traffic_selector_t, hash, u_int,
647
  private_traffic_selector_t *this, u_int hash)
648
0
{
649
0
  return chunk_hash_inc(get_from_address(this),
650
0
      chunk_hash_inc(get_to_address(this),
651
0
       chunk_hash_inc(chunk_from_thing(this->from_port),
652
0
        chunk_hash_inc(chunk_from_thing(this->to_port),
653
0
         chunk_hash_inc(chunk_from_thing(this->protocol),
654
0
        hash)))));
655
0
}
656
657
METHOD(traffic_selector_t, destroy, void,
658
  private_traffic_selector_t *this)
659
0
{
660
0
  free(this);
661
0
}
662
663
/**
664
 * Compare two integers
665
 */
666
static int compare_int(int a, int b)
667
0
{
668
0
  return a - b;
669
0
}
670
671
/*
672
 * See header
673
 */
674
int traffic_selector_cmp(traffic_selector_t *a_pub, traffic_selector_t *b_pub,
675
             void *opts)
676
0
{
677
0
  private_traffic_selector_t *a, *b;
678
0
  size_t len;
679
0
  int res;
680
681
0
  a = (private_traffic_selector_t*)a_pub;
682
0
  b = (private_traffic_selector_t*)b_pub;
683
684
  /* IPv4 before IPv6 */
685
0
  res = compare_int(a->type, b->type);
686
0
  if (res)
687
0
  {
688
0
    return res;
689
0
  }
690
0
  len = TS_IP_LEN(a);
691
  /* lower starting subnets first */
692
0
  res = memcmp(a->from, b->from, len);
693
0
  if (res)
694
0
  {
695
0
    return res;
696
0
  }
697
  /* larger subnets first */
698
0
  res = memcmp(b->to, a->to, len);
699
0
  if (res)
700
0
  {
701
0
    return res;
702
0
  }
703
  /* lower protocols first */
704
0
  res = compare_int(a->protocol, b->protocol);
705
0
  if (res)
706
0
  {
707
0
    return res;
708
0
  }
709
  /* lower starting ports first */
710
0
  res = compare_int(a->from_port, b->from_port);
711
0
  if (res)
712
0
  {
713
0
    return res;
714
0
  }
715
  /* larger port ranges first */
716
0
  return compare_int(b->to_port, a->to_port);
717
0
}
718
719
/*
720
 * see header
721
 */
722
traffic_selector_t *traffic_selector_create_from_bytes(uint8_t protocol,
723
                        ts_type_t type,
724
                        chunk_t from, uint16_t from_port,
725
                        chunk_t to, uint16_t to_port)
726
0
{
727
0
  private_traffic_selector_t *this = traffic_selector_create(protocol, type,
728
0
                              from_port, to_port);
729
730
0
  if (!this)
731
0
  {
732
0
    return NULL;
733
0
  }
734
0
  if (from.len != to.len || from.len != TS_IP_LEN(this))
735
0
  {
736
0
    free(this);
737
0
    return NULL;
738
0
  }
739
0
  memcpy(this->from, from.ptr, from.len);
740
0
  memcpy(this->to, to.ptr, to.len);
741
0
  calc_netbits(this);
742
0
  return &this->public;
743
0
}
744
745
/*
746
 * see header
747
 */
748
traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type,
749
                        chunk_t from, chunk_t to)
750
0
{
751
0
  private_traffic_selector_t *this = traffic_selector_create(0, type, 0, 65535);
752
0
  size_t len;
753
754
0
  if (!this)
755
0
  {
756
0
    return NULL;
757
0
  }
758
0
  len = TS_IP_LEN(this);
759
760
0
  memset(this->from, 0x00, len);
761
0
  memset(this->to  , 0xff, len);
762
763
0
  if (from.len > 1)
764
0
  {
765
0
    memcpy(this->from, from.ptr+1, from.len-1);
766
0
  }
767
0
  if (to.len > 1)
768
0
  {
769
0
    uint8_t mask = to.ptr[0] ? (1 << to.ptr[0]) - 1 : 0;
770
771
0
    memcpy(this->to, to.ptr+1, to.len-1);
772
0
    this->to[to.len-2] |= mask;
773
0
  }
774
0
  calc_netbits(this);
775
0
  return &this->public;
776
0
}
777
778
/*
779
 * see header
780
 */
781
traffic_selector_t *traffic_selector_create_from_subnet(host_t *net,
782
              uint8_t netbits, uint8_t protocol,
783
              uint16_t from_port, uint16_t to_port)
784
0
{
785
0
  private_traffic_selector_t *this;
786
0
  ts_type_t type;
787
0
  chunk_t from;
788
789
0
  switch (net->get_family(net))
790
0
  {
791
0
    case AF_INET:
792
0
      type = TS_IPV4_ADDR_RANGE;
793
0
      break;
794
0
    case AF_INET6:
795
0
      type = TS_IPV6_ADDR_RANGE;
796
0
      break;
797
0
    default:
798
0
      net->destroy(net);
799
0
      return NULL;
800
0
  }
801
802
0
  this = traffic_selector_create(protocol, type, from_port, to_port);
803
804
0
  from = net->get_address(net);
805
0
  memcpy(this->from, from.ptr, from.len);
806
0
  netbits = min(netbits, TS_IP_LEN(this) * 8);
807
0
  calc_range(this, netbits);
808
0
  net->destroy(net);
809
0
  return &this->public;
810
0
}
811
812
/*
813
 * see header
814
 */
815
traffic_selector_t *traffic_selector_create_from_string(
816
                    uint8_t protocol, ts_type_t type,
817
                    char *from_addr, uint16_t from_port,
818
                    char *to_addr, uint16_t to_port)
819
0
{
820
0
  private_traffic_selector_t *this;
821
0
  int family;
822
823
0
  switch (type)
824
0
  {
825
0
    case TS_IPV4_ADDR_RANGE:
826
0
      family = AF_INET;
827
0
      break;
828
0
    case TS_IPV6_ADDR_RANGE:
829
0
      family = AF_INET6;
830
0
      break;
831
0
    default:
832
0
      return NULL;
833
0
  }
834
835
0
  this = traffic_selector_create(protocol, type, from_port, to_port);
836
837
0
  if (inet_pton(family, from_addr, this->from) != 1 ||
838
0
    inet_pton(family, to_addr, this->to) != 1)
839
0
  {
840
0
    free(this);
841
0
    return NULL;
842
0
  }
843
0
  calc_netbits(this);
844
0
  return &this->public;
845
0
}
846
847
/*
848
 * see header
849
 */
850
traffic_selector_t *traffic_selector_create_from_cidr(
851
                    char *string, uint8_t protocol,
852
                    uint16_t from_port, uint16_t to_port)
853
0
{
854
0
  host_t *net;
855
0
  int bits;
856
857
0
  net = host_create_from_subnet(string, &bits);
858
0
  if (net)
859
0
  {
860
0
    return traffic_selector_create_from_subnet(net, bits, protocol,
861
0
                           from_port, to_port);
862
0
  }
863
0
  return NULL;
864
0
}
865
866
/*
867
 * see header
868
 */
869
traffic_selector_t *traffic_selector_create_dynamic(uint8_t protocol,
870
                  uint16_t from_port, uint16_t to_port)
871
0
{
872
0
  private_traffic_selector_t *this = traffic_selector_create(
873
0
              protocol, TS_IPV4_ADDR_RANGE, from_port, to_port);
874
875
0
  memset(this->from, 0, sizeof(this->from));
876
0
  memset(this->to, 0xFF, sizeof(this->to));
877
0
  this->netbits = 0;
878
0
  this->dynamic = TRUE;
879
880
0
  return &this->public;
881
0
}
882
883
/*
884
 * see declaration
885
 */
886
static private_traffic_selector_t *traffic_selector_create(uint8_t protocol,
887
            ts_type_t type, uint16_t from_port, uint16_t to_port)
888
0
{
889
0
  private_traffic_selector_t *this;
890
891
  /* sanity check */
892
0
  if (type != TS_IPV4_ADDR_RANGE && type != TS_IPV6_ADDR_RANGE)
893
0
  {
894
0
    return NULL;
895
0
  }
896
897
0
  INIT(this,
898
0
    .public = {
899
0
      .get_subset = _get_subset,
900
0
      .equals = _equals,
901
0
      .get_from_address = _get_from_address,
902
0
      .get_to_address = _get_to_address,
903
0
      .get_from_port = _get_from_port,
904
0
      .get_to_port = _get_to_port,
905
0
      .get_type = _get_type,
906
0
      .get_protocol = _get_protocol,
907
0
      .is_host = _is_host,
908
0
      .is_dynamic = _is_dynamic,
909
0
      .is_contained_in = _is_contained_in,
910
0
      .includes = _includes,
911
0
      .set_address = _set_address,
912
0
      .to_subnet = _to_subnet,
913
0
      .clone = _clone_,
914
0
      .hash = _hash,
915
0
      .destroy = _destroy,
916
0
    },
917
0
    .from_port = from_port,
918
0
    .to_port = to_port,
919
0
    .protocol = protocol,
920
0
    .type = type,
921
0
  );
922
0
  if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6)
923
0
  {
924
0
    this->from_port = from_port < 256 ? from_port << 8 : from_port;
925
0
    this->to_port = to_port < 256 ? to_port << 8 : to_port;
926
0
  }
927
0
  return this;
928
0
}