Annotation of embedaddon/strongswan/src/libipsec/ipsec_policy_mgr.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2012 Tobias Brunner
        !             3:  * Copyright (C) 2012 Giuliano Grassi
        !             4:  * Copyright (C) 2012 Ralf Sager
        !             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 "ipsec_policy_mgr.h"
        !            19: 
        !            20: #include <utils/debug.h>
        !            21: #include <threading/rwlock.h>
        !            22: #include <collections/linked_list.h>
        !            23: 
        !            24: /** Base priority for installed policies */
        !            25: #define PRIO_BASE 384
        !            26: 
        !            27: typedef struct private_ipsec_policy_mgr_t private_ipsec_policy_mgr_t;
        !            28: 
        !            29: /**
        !            30:  * Private additions to ipsec_policy_mgr_t.
        !            31:  */
        !            32: struct private_ipsec_policy_mgr_t {
        !            33: 
        !            34:        /**
        !            35:         * Public members of ipsec_policy_mgr_t.
        !            36:         */
        !            37:        ipsec_policy_mgr_t public;
        !            38: 
        !            39:        /**
        !            40:         * Installed policies (ipsec_policy_entry_t*)
        !            41:         */
        !            42:        linked_list_t *policies;
        !            43: 
        !            44:        /**
        !            45:         * Lock to safely access the list of policies
        !            46:         */
        !            47:        rwlock_t *lock;
        !            48: 
        !            49: };
        !            50: 
        !            51: /**
        !            52:  * Helper struct to store policies in a list sorted by the same pseudo-priority
        !            53:  * used by the NETLINK kernel interface.
        !            54:  */
        !            55: typedef struct {
        !            56: 
        !            57:        /**
        !            58:         * Priority used to sort policies
        !            59:         */
        !            60:        uint32_t priority;
        !            61: 
        !            62:        /**
        !            63:         * The policy
        !            64:         */
        !            65:        ipsec_policy_t *policy;
        !            66: 
        !            67: } ipsec_policy_entry_t;
        !            68: 
        !            69: /**
        !            70:  * Calculate the pseudo-priority to sort policies.  This is the same algorithm
        !            71:  * used by the NETLINK kernel interface (i.e. high priority -> low value).
        !            72:  */
        !            73: static uint32_t calculate_priority(policy_priority_t policy_priority,
        !            74:                                                                        traffic_selector_t *src,
        !            75:                                                                        traffic_selector_t *dst)
        !            76: {
        !            77:        uint32_t priority = PRIO_BASE;
        !            78:        uint16_t port;
        !            79:        uint8_t mask, proto;
        !            80:        host_t *net;
        !            81: 
        !            82:        switch (policy_priority)
        !            83:        {
        !            84:                case POLICY_PRIORITY_FALLBACK:
        !            85:                        priority <<= 1;
        !            86:                        /* fall-through */
        !            87:                case POLICY_PRIORITY_ROUTED:
        !            88:                        priority <<= 1;
        !            89:                        /* fall-through */
        !            90:                case POLICY_PRIORITY_DEFAULT:
        !            91:                        priority <<= 1;
        !            92:                        /* fall-through */
        !            93:                case POLICY_PRIORITY_PASS:
        !            94:                        break;
        !            95:        }
        !            96:        /* calculate priority based on selector size, small size = high prio */
        !            97:        src->to_subnet(src, &net, &mask);
        !            98:        priority -= mask;
        !            99:        proto = src->get_protocol(src);
        !           100:        port = net->get_port(net);
        !           101:        net->destroy(net);
        !           102: 
        !           103:        dst->to_subnet(dst, &net, &mask);
        !           104:        priority -= mask;
        !           105:        proto = max(proto, dst->get_protocol(dst));
        !           106:        port = max(port, net->get_port(net));
        !           107:        net->destroy(net);
        !           108: 
        !           109:        priority <<= 2; /* make some room for the two flags */
        !           110:        priority += port ? 0 : 2;
        !           111:        priority += proto ? 0 : 1;
        !           112:        return priority;
        !           113: }
        !           114: 
        !           115: /**
        !           116:  * Create a policy entry
        !           117:  */
        !           118: static ipsec_policy_entry_t *policy_entry_create(ipsec_policy_t *policy)
        !           119: {
        !           120:        ipsec_policy_entry_t *this;
        !           121: 
        !           122:        INIT(this,
        !           123:                .policy = policy,
        !           124:                .priority = calculate_priority(policy->get_priority(policy),
        !           125:                                                                           policy->get_source_ts(policy),
        !           126:                                                                           policy->get_destination_ts(policy)),
        !           127:        );
        !           128:        return this;
        !           129: }
        !           130: 
        !           131: /**
        !           132:  * Destroy a policy entry
        !           133:  */
        !           134: static void policy_entry_destroy(ipsec_policy_entry_t *this)
        !           135: {
        !           136:        this->policy->destroy(this->policy);
        !           137:        free(this);
        !           138: }
        !           139: 
        !           140: METHOD(ipsec_policy_mgr_t, add_policy, status_t,
        !           141:        private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst,
        !           142:        traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
        !           143:        policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
        !           144:        policy_priority_t priority)
        !           145: {
        !           146:        enumerator_t *enumerator;
        !           147:        ipsec_policy_entry_t *entry, *current;
        !           148:        ipsec_policy_t *policy;
        !           149: 
        !           150:        if (type != POLICY_IPSEC || direction == POLICY_FWD)
        !           151:        {       /* we ignore these policies as we currently have no use for them */
        !           152:                return SUCCESS;
        !           153:        }
        !           154: 
        !           155:        DBG2(DBG_ESP, "adding policy %R === %R %N", src_ts, dst_ts,
        !           156:                 policy_dir_names, direction);
        !           157: 
        !           158:        policy = ipsec_policy_create(src, dst, src_ts, dst_ts, direction, type, sa,
        !           159:                                                                 mark, priority);
        !           160:        entry = policy_entry_create(policy);
        !           161: 
        !           162:        this->lock->write_lock(this->lock);
        !           163:        enumerator = this->policies->create_enumerator(this->policies);
        !           164:        while (enumerator->enumerate(enumerator, (void**)&current))
        !           165:        {
        !           166:                if (current->priority >= entry->priority)
        !           167:                {
        !           168:                        break;
        !           169:                }
        !           170:        }
        !           171:        this->policies->insert_before(this->policies, enumerator, entry);
        !           172:        enumerator->destroy(enumerator);
        !           173:        this->lock->unlock(this->lock);
        !           174:        return SUCCESS;
        !           175: }
        !           176: 
        !           177: METHOD(ipsec_policy_mgr_t, del_policy, status_t,
        !           178:        private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst,
        !           179:        traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
        !           180:        policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
        !           181:        policy_priority_t policy_priority)
        !           182: {
        !           183:        enumerator_t *enumerator;
        !           184:        ipsec_policy_entry_t *current, *found = NULL;
        !           185:        uint32_t priority;
        !           186: 
        !           187:        if (type != POLICY_IPSEC || direction == POLICY_FWD)
        !           188:        {       /* we ignore these policies as we currently have no use for them */
        !           189:                return SUCCESS;
        !           190:        }
        !           191:        DBG2(DBG_ESP, "deleting policy %R === %R %N", src_ts, dst_ts,
        !           192:                 policy_dir_names, direction);
        !           193: 
        !           194:        priority = calculate_priority(policy_priority, src_ts, dst_ts);
        !           195: 
        !           196:        this->lock->write_lock(this->lock);
        !           197:        enumerator = this->policies->create_enumerator(this->policies);
        !           198:        while (enumerator->enumerate(enumerator, (void**)&current))
        !           199:        {
        !           200:                if (current->priority == priority &&
        !           201:                        current->policy->match(current->policy, src_ts, dst_ts, direction,
        !           202:                                                                   sa->reqid, mark, policy_priority))
        !           203:                {
        !           204:                        this->policies->remove_at(this->policies, enumerator);
        !           205:                        found = current;
        !           206:                        break;
        !           207:                }
        !           208:        }
        !           209:        enumerator->destroy(enumerator);
        !           210:        this->lock->unlock(this->lock);
        !           211:        if (found)
        !           212:        {
        !           213:                policy_entry_destroy(found);
        !           214:                return SUCCESS;
        !           215:        }
        !           216:        return FAILED;
        !           217: }
        !           218: 
        !           219: METHOD(ipsec_policy_mgr_t, flush_policies, status_t,
        !           220:        private_ipsec_policy_mgr_t *this)
        !           221: {
        !           222:        ipsec_policy_entry_t *entry;
        !           223: 
        !           224:        DBG2(DBG_ESP, "flushing policies");
        !           225: 
        !           226:        this->lock->write_lock(this->lock);
        !           227:        while (this->policies->remove_last(this->policies,
        !           228:                                                                          (void**)&entry) == SUCCESS)
        !           229:        {
        !           230:                policy_entry_destroy(entry);
        !           231:        }
        !           232:        this->lock->unlock(this->lock);
        !           233:        return SUCCESS;
        !           234: }
        !           235: 
        !           236: METHOD(ipsec_policy_mgr_t, find_by_packet, ipsec_policy_t*,
        !           237:        private_ipsec_policy_mgr_t *this, ip_packet_t *packet, bool inbound,
        !           238:        uint32_t reqid)
        !           239: {
        !           240:        enumerator_t *enumerator;
        !           241:        ipsec_policy_entry_t *current;
        !           242:        ipsec_policy_t *found = NULL;
        !           243: 
        !           244:        this->lock->read_lock(this->lock);
        !           245:        enumerator = this->policies->create_enumerator(this->policies);
        !           246:        while (enumerator->enumerate(enumerator, (void**)&current))
        !           247:        {
        !           248:                ipsec_policy_t *policy = current->policy;
        !           249: 
        !           250:                if ((inbound == (policy->get_direction(policy) == POLICY_IN)) &&
        !           251:                         policy->match_packet(policy, packet))
        !           252:                {
        !           253:                        if (reqid == 0 || reqid == policy->get_reqid(policy))
        !           254:                        {
        !           255:                                found = policy->get_ref(policy);
        !           256:                                break;
        !           257:                        }
        !           258:                }
        !           259:        }
        !           260:        enumerator->destroy(enumerator);
        !           261:        this->lock->unlock(this->lock);
        !           262:        return found;
        !           263: }
        !           264: 
        !           265: METHOD(ipsec_policy_mgr_t, destroy, void,
        !           266:        private_ipsec_policy_mgr_t *this)
        !           267: {
        !           268:        flush_policies(this);
        !           269:        this->policies->destroy(this->policies);
        !           270:        this->lock->destroy(this->lock);
        !           271:        free(this);
        !           272: }
        !           273: 
        !           274: /**
        !           275:  * Described in header.
        !           276:  */
        !           277: ipsec_policy_mgr_t *ipsec_policy_mgr_create()
        !           278: {
        !           279:        private_ipsec_policy_mgr_t *this;
        !           280: 
        !           281:        INIT(this,
        !           282:                .public = {
        !           283:                        .add_policy = _add_policy,
        !           284:                        .del_policy = _del_policy,
        !           285:                        .flush_policies = _flush_policies,
        !           286:                        .find_by_packet = _find_by_packet,
        !           287:                        .destroy = _destroy,
        !           288:                },
        !           289:                .policies = linked_list_create(),
        !           290:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        !           291:        );
        !           292: 
        !           293:        return &this->public;
        !           294: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>