Annotation of embedaddon/strongswan/src/libipsec/ipsec_policy_mgr.c, revision 1.1.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>