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