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>