Annotation of embedaddon/strongswan/src/libcharon/plugins/forecast/forecast_listener.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2015 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * Copyright (C) 2010-2014 Martin Willi
                      6:  * Copyright (C) 2010-2014 revosec AG
                      7:  *
                      8:  * This program is free software; you can redistribute it and/or modify it
                      9:  * under the terms of the GNU General Public License as published by the
                     10:  * Free Software Foundation; either version 2 of the License, or (at your
                     11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     12:  *
                     13:  * This program is distributed in the hope that it will be useful, but
                     14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     16:  * for more details.
                     17:  */
                     18: 
                     19: #include "forecast_listener.h"
                     20: 
                     21: #include <errno.h>
                     22: #include <libiptc/libiptc.h>
                     23: #include <linux/netfilter/xt_MARK.h>
                     24: #include <linux/netfilter/xt_esp.h>
                     25: 
                     26: #include <daemon.h>
                     27: #include <collections/array.h>
                     28: #include <collections/hashtable.h>
                     29: #include <threading/rwlock.h>
                     30: 
                     31: /**
                     32:  * Add a struct at the current position in the buffer
                     33:  */
                     34: #define ADD_STRUCT(pos, st, ...) ({\
                     35:        typeof(pos) _cur = pos; pos += XT_ALIGN(sizeof(st));\
                     36:        *(st*)_cur = (st){ __VA_ARGS__ };\
                     37:        (st*)_cur;\
                     38: })
                     39: 
                     40: typedef struct private_forecast_listener_t private_forecast_listener_t;
                     41: 
                     42: /**
                     43:  * Private data of an forecast_listener_t object.
                     44:  */
                     45: struct private_forecast_listener_t {
                     46: 
                     47:        /**
                     48:         * Public forecast_listener_t interface.
                     49:         */
                     50:        forecast_listener_t public;
                     51: 
                     52:        /**
                     53:         * List of entries
                     54:         */
                     55:        linked_list_t *entries;
                     56: 
                     57:        /**
                     58:         * RWlock for IP list
                     59:         */
                     60:        rwlock_t *lock;
                     61: 
                     62:        /**
                     63:         * Configs we do reinjection
                     64:         */
                     65:        char *reinject_configs;
                     66: 
                     67:        /**
                     68:         * Broadcast address on LAN interface, network order
                     69:         */
                     70:        uint32_t broadcast;
                     71: };
                     72: 
                     73: /**
                     74:  * Hashtable entry
                     75:  */
                     76: typedef struct {
                     77:        /** local traffic selectors */
                     78:        array_t *lts;
                     79:        /** remote traffic selectors */
                     80:        array_t *rts;
                     81:        /** firewall mark used by CHILD_SA */
                     82:        u_int mark;
                     83:        /** local IKE_SA endpoint */
                     84:        host_t *lhost;
                     85:        /** remote IKE_SA endpoint */
                     86:        host_t *rhost;
                     87:        /** inbound SPI */
                     88:        uint32_t spi;
                     89:        /** use UDP encapsulation */
                     90:        bool encap;
                     91:        /** whether we should allow reencapsulation of IPsec received forecasts */
                     92:        bool reinject;
                     93:        /** broadcast address used for that entry */
                     94:        uint32_t broadcast;
                     95: } entry_t;
                     96: 
                     97: /**
                     98:  * Destroy an entry
                     99:  */
                    100: static void entry_destroy(entry_t *entry)
                    101: {
                    102:        if (entry)
                    103:        {
                    104:                entry->lhost->destroy(entry->lhost);
                    105:                entry->rhost->destroy(entry->rhost);
                    106:                array_destroy_offset(entry->lts, offsetof(traffic_selector_t, destroy));
                    107:                array_destroy_offset(entry->rts, offsetof(traffic_selector_t, destroy));
                    108:                free(entry);
                    109:        }
                    110: }
                    111: 
                    112: /**
                    113:  * Convert an (IPv4) traffic selector to an address and mask
                    114:  */
                    115: static bool ts2in(traffic_selector_t *ts,
                    116:                                  struct in_addr *addr, struct in_addr *mask)
                    117: {
                    118:        uint8_t bits;
                    119:        host_t *net;
                    120: 
                    121:        if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE &&
                    122:                ts->to_subnet(ts, &net, &bits))
                    123:        {
                    124:                memcpy(&addr->s_addr, net->get_address(net).ptr, 4);
                    125:                net->destroy(net);
                    126:                mask->s_addr = htonl(0xffffffffU << (32 - bits));
                    127:                return TRUE;
                    128:        }
                    129:        return FALSE;
                    130: }
                    131: 
                    132: /**
                    133:  * Convert an (IPv4) host to an address with mask
                    134:  */
                    135: static bool host2in(host_t *host, struct in_addr *addr, struct in_addr *mask)
                    136: {
                    137:        if (host->get_family(host) == AF_INET)
                    138:        {
                    139:                memcpy(&addr->s_addr, host->get_address(host).ptr, 4);
                    140:                mask->s_addr = ~0;
                    141:                return TRUE;
                    142:        }
                    143:        return FALSE;
                    144: }
                    145: 
                    146: /**
                    147:  * Add or remove a rule to/from the specified chain
                    148:  */
                    149: static bool manage_rule(struct iptc_handle *ipth, const char *chain,
                    150:                                                bool add, struct ipt_entry *e)
                    151: {
                    152:        if (add)
                    153:        {
                    154:                if (!iptc_insert_entry(chain, e, 0, ipth))
                    155:                {
                    156:                        DBG1(DBG_CFG, "appending %s rule failed: %s",
                    157:                                 chain, iptc_strerror(errno));
                    158:                        return FALSE;
                    159:                }
                    160:        }
                    161:        else
                    162:        {
                    163:                u_char matchmask[e->next_offset];
                    164: 
                    165:                memset(matchmask, 255, sizeof(matchmask));
                    166:                if (!iptc_delete_entry(chain, e, matchmask, ipth))
                    167:                {
                    168:                        DBG1(DBG_CFG, "deleting %s rule failed: %s",
                    169:                                 chain, iptc_strerror(errno));
                    170:                        return FALSE;
                    171:                }
                    172:        }
                    173:        return TRUE;
                    174: }
                    175: 
                    176: /**
                    177:  * Add rule marking UDP-encapsulated ESP packets to match the correct policy
                    178:  */
                    179: static bool manage_pre_esp_in_udp(struct iptc_handle *ipth,
                    180:                                                                  entry_t *entry, bool add)
                    181: {
                    182:        uint16_t match_size     = XT_ALIGN(sizeof(struct ipt_entry_match)) +
                    183:                                                          XT_ALIGN(sizeof(struct xt_udp));
                    184:        uint16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry)) + match_size;
                    185:        uint16_t target_size    = XT_ALIGN(sizeof(struct ipt_entry_target)) +
                    186:                                                          XT_ALIGN(sizeof(struct xt_mark_tginfo2));
                    187:        uint16_t entry_size     = target_offset + target_size;
                    188:        u_char ipt[entry_size], *pos = ipt;
                    189:        struct ipt_entry *e;
                    190: 
                    191:        memset(ipt, 0, sizeof(ipt));
                    192:        e = ADD_STRUCT(pos, struct ipt_entry,
                    193:                .target_offset = target_offset,
                    194:                .next_offset = entry_size,
                    195:                .ip = {
                    196:                        .proto = IPPROTO_UDP,
                    197:                },
                    198:        );
                    199:        if (!host2in(entry->lhost, &e->ip.dst, &e->ip.dmsk) ||
                    200:                !host2in(entry->rhost, &e->ip.src, &e->ip.smsk))
                    201:        {
                    202:                return FALSE;
                    203:        }
                    204:        ADD_STRUCT(pos, struct ipt_entry_match,
                    205:                .u = {
                    206:                        .user = {
                    207:                                .match_size = match_size,
                    208:                                .name = "udp",
                    209:                        },
                    210:                },
                    211:        );
                    212:        ADD_STRUCT(pos, struct xt_udp,
                    213:                .spts = {
                    214:                        entry->rhost->get_port(entry->rhost),
                    215:                        entry->rhost->get_port(entry->rhost)
                    216:                },
                    217:                .dpts = {
                    218:                        entry->lhost->get_port(entry->lhost),
                    219:                        entry->lhost->get_port(entry->lhost)
                    220:                },
                    221:        );
                    222:        ADD_STRUCT(pos, struct ipt_entry_target,
                    223:                .u = {
                    224:                        .user = {
                    225:                                .target_size = target_size,
                    226:                                .name = "MARK",
                    227:                                .revision = 2,
                    228:                        },
                    229:                },
                    230:        );
                    231:        ADD_STRUCT(pos, struct xt_mark_tginfo2,
                    232:                .mark = entry->mark,
                    233:                .mask = ~0,
                    234:        );
                    235:        return manage_rule(ipth, "PREROUTING", add, e);
                    236: }
                    237: 
                    238: /**
                    239:  * Add rule marking non-encapsulated ESP packets to match the correct policy
                    240:  */
                    241: static bool manage_pre_esp(struct iptc_handle *ipth, entry_t *entry, bool add)
                    242: {
                    243:        uint16_t match_size     = XT_ALIGN(sizeof(struct ipt_entry_match)) +
                    244:                                                          XT_ALIGN(sizeof(struct xt_esp));
                    245:        uint16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry)) + match_size;
                    246:        uint16_t target_size    = XT_ALIGN(sizeof(struct ipt_entry_target)) +
                    247:                                                          XT_ALIGN(sizeof(struct xt_mark_tginfo2));
                    248:        uint16_t entry_size     = target_offset + target_size;
                    249:        u_char ipt[entry_size], *pos = ipt;
                    250:        struct ipt_entry *e;
                    251: 
                    252:        memset(ipt, 0, sizeof(ipt));
                    253:        e = ADD_STRUCT(pos, struct ipt_entry,
                    254:                .target_offset = target_offset,
                    255:                .next_offset = entry_size,
                    256:                .ip = {
                    257:                        .proto = IPPROTO_ESP,
                    258:                },
                    259:        );
                    260:        if (!host2in(entry->lhost, &e->ip.dst, &e->ip.dmsk) ||
                    261:                !host2in(entry->rhost, &e->ip.src, &e->ip.smsk))
                    262:        {
                    263:                return FALSE;
                    264:        }
                    265:        ADD_STRUCT(pos, struct ipt_entry_match,
                    266:                .u = {
                    267:                        .user = {
                    268:                                .match_size = match_size,
                    269:                                .name = "esp",
                    270:                        },
                    271:                },
                    272:        );
                    273:        ADD_STRUCT(pos, struct xt_esp,
                    274:                .spis = { htonl(entry->spi), htonl(entry->spi) },
                    275:        );
                    276:        ADD_STRUCT(pos, struct ipt_entry_target,
                    277:                .u = {
                    278:                        .user = {
                    279:                                .target_size = target_size,
                    280:                                .name = "MARK",
                    281:                                .revision = 2,
                    282:                        },
                    283:                },
                    284:        );
                    285:        ADD_STRUCT(pos, struct xt_mark_tginfo2,
                    286:                .mark = entry->mark,
                    287:                .mask = ~0,
                    288:        );
                    289:        return manage_rule(ipth, "PREROUTING", add, e);
                    290: }
                    291: 
                    292: /**
                    293:  * Add rule marking ESP packets to match the correct policy
                    294:  */
                    295: static bool manage_pre(struct iptc_handle *ipth, entry_t *entry, bool add)
                    296: {
                    297:        if (entry->encap)
                    298:        {
                    299:                return manage_pre_esp_in_udp(ipth, entry, add);
                    300:        }
                    301:        return manage_pre_esp(ipth, entry, add);
                    302: }
                    303: 
                    304: /**
                    305:  * Add rule handling outbound traffic to use correct mark
                    306:  */
                    307: static bool manage_out(struct iptc_handle *ipth, entry_t *entry, bool add)
                    308: {
                    309:        uint16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry));
                    310:        uint16_t target_size    = XT_ALIGN(sizeof(struct ipt_entry_target)) +
                    311:                                                          XT_ALIGN(sizeof(struct xt_mark_tginfo2));
                    312:        uint16_t entry_size     = target_offset + target_size;
                    313:        u_char ipt[entry_size], *pos = ipt;
                    314:        struct ipt_entry *e;
                    315: 
                    316:        memset(ipt, 0, sizeof(ipt));
                    317:        e = ADD_STRUCT(pos, struct ipt_entry,
                    318:                .target_offset = target_offset,
                    319:                .next_offset = entry_size,
                    320:        );
                    321:        ADD_STRUCT(pos, struct ipt_entry_target,
                    322:                .u = {
                    323:                        .user = {
                    324:                                .target_size = target_size,
                    325:                                .name = "MARK",
                    326:                                .revision = 2,
                    327:                        },
                    328:                },
                    329:        );
                    330:        ADD_STRUCT(pos, struct xt_mark_tginfo2,
                    331:                .mark = entry->mark,
                    332:                .mask = ~0,
                    333:        );
                    334: 
                    335:        enumerator_t *enumerator;
                    336:        traffic_selector_t *ts;
                    337: 
                    338:        enumerator = array_create_enumerator(entry->rts);
                    339:        while (enumerator->enumerate(enumerator, &ts))
                    340:        {
                    341:                if (!ts2in(ts, &e->ip.dst, &e->ip.dmsk))
                    342:                {
                    343:                        continue;
                    344:                }
                    345:                if (e->ip.dst.s_addr == 0xffffffff ||
                    346:                        e->ip.dst.s_addr == entry->broadcast ||
                    347:                        memeq(&e->ip.dst.s_addr, "\xe0", 1))
                    348:                {
                    349:                        /* skip broadcast/multicast selectors, they are shared and the mark
                    350:                         * is set by the socket we use for reinjection */
                    351:                        continue;
                    352:                }
                    353:                if (!manage_rule(ipth, "PREROUTING", add, e) ||
                    354:                        !manage_rule(ipth, "OUTPUT", add, e))
                    355:                {
                    356:                        enumerator->destroy(enumerator);
                    357:                        return FALSE;
                    358:                }
                    359:        }
                    360:        enumerator->destroy(enumerator);
                    361: 
                    362:        return TRUE;
                    363: }
                    364: 
                    365: /**
                    366:  * Check if config is whitelisted to reinject traffic
                    367:  */
                    368: static bool is_reinject_config(private_forecast_listener_t *this, char *name)
                    369: {
                    370:        enumerator_t *enumerator;
                    371:        bool reinject = FALSE;
                    372:        char *token;
                    373: 
                    374:        enumerator = enumerator_create_token(this->reinject_configs, ",", " ");
                    375:        while (enumerator->enumerate(enumerator, &token))
                    376:        {
                    377:                if (streq(token, name))
                    378:                {
                    379:                        reinject = TRUE;
                    380:                        break;
                    381:                }
                    382:        }
                    383:        enumerator->destroy(enumerator);
                    384: 
                    385:        return reinject;
                    386: }
                    387: 
                    388: /**
                    389:  * Add rules and entry for given CHILD_SA
                    390:  */
                    391: static bool add_entry(private_forecast_listener_t *this,
                    392:                                          struct iptc_handle *ipth, host_t *lhost, host_t *rhost,
                    393:                                          child_sa_t *child_sa, bool encap)
                    394: {
                    395:        enumerator_t *enumerator;
                    396:        traffic_selector_t *ts;
                    397:        entry_t *entry;
                    398: 
                    399:        INIT(entry,
                    400:                .lts = array_create(0, 0),
                    401:                .rts = array_create(0, 0),
                    402:                .lhost = lhost->clone(lhost),
                    403:                .rhost = rhost->clone(rhost),
                    404:                .spi = child_sa->get_spi(child_sa, TRUE),
                    405:                .encap = encap,
                    406:                .mark = child_sa->get_mark(child_sa, TRUE).value,
                    407:                .reinject = is_reinject_config(this, child_sa->get_name(child_sa)),
                    408:                .broadcast = this->broadcast,
                    409:        );
                    410: 
                    411:        enumerator = child_sa->create_ts_enumerator(child_sa, TRUE);
                    412:        while (enumerator->enumerate(enumerator, &ts))
                    413:        {
                    414:                array_insert(entry->lts, ARRAY_TAIL, ts->clone(ts));
                    415:        }
                    416:        enumerator->destroy(enumerator);
                    417: 
                    418:        enumerator = child_sa->create_ts_enumerator(child_sa, FALSE);
                    419:        while (enumerator->enumerate(enumerator, &ts))
                    420:        {
                    421:                array_insert(entry->rts, ARRAY_TAIL, ts->clone(ts));
                    422:        }
                    423:        enumerator->destroy(enumerator);
                    424: 
                    425:        if (manage_pre(ipth, entry, TRUE) &&
                    426:                manage_out(ipth, entry, TRUE))
                    427:        {
                    428:                this->lock->write_lock(this->lock);
                    429:                this->entries->insert_last(this->entries, entry);
                    430:                this->lock->unlock(this->lock);
                    431:                return TRUE;
                    432:        }
                    433:        entry_destroy(entry);
                    434:        return FALSE;
                    435: }
                    436: 
                    437: /**
                    438:  * Remove an entry and rules for a given mark
                    439:  */
                    440: static bool remove_entry(private_forecast_listener_t *this,
                    441:                                                 struct iptc_handle *ipth, child_sa_t *child_sa)
                    442: {
                    443:        enumerator_t *enumerator;
                    444:        entry_t *entry;
                    445:        bool done = FALSE;
                    446: 
                    447:        this->lock->write_lock(this->lock);
                    448:        enumerator = this->entries->create_enumerator(this->entries);
                    449:        while (enumerator->enumerate(enumerator, &entry))
                    450:        {
                    451:                if (entry->mark == child_sa->get_mark(child_sa, TRUE).value)
                    452:                {
                    453:                        this->entries->remove_at(this->entries, enumerator);
                    454:                        if (manage_pre(ipth, entry, FALSE) &&
                    455:                                manage_out(ipth, entry, FALSE))
                    456:                        {
                    457:                                done = TRUE;
                    458:                        }
                    459:                        entry_destroy(entry);
                    460:                        break;
                    461:                }
                    462:        }
                    463:        enumerator->destroy(enumerator);
                    464:        this->lock->unlock(this->lock);
                    465: 
                    466:        return done;
                    467: }
                    468: 
                    469: /**
                    470:  * Initialize iptables handle, log error
                    471:  */
                    472: static struct iptc_handle* init_handle()
                    473: {
                    474:        struct iptc_handle *ipth;
                    475: 
                    476:        ipth = iptc_init("mangle");
                    477:        if (ipth)
                    478:        {
                    479:                return ipth;
                    480:        }
                    481:        DBG1(DBG_CFG, "initializing iptables failed: %s", iptc_strerror(errno));
                    482:        return NULL;
                    483: }
                    484: 
                    485: /**
                    486:  * Commit iptables rules, log error
                    487:  */
                    488: static bool commit_handle(struct iptc_handle *ipth)
                    489: {
                    490:        if (iptc_commit(ipth))
                    491:        {
                    492:                return TRUE;
                    493:        }
                    494:        DBG1(DBG_CFG, "forecast iptables commit failed: %s", iptc_strerror(errno));
                    495:        return FALSE;
                    496: }
                    497: 
                    498: /**
                    499:  * Check if we should handle the given CHILD_SA
                    500:  */
                    501: static bool handle_sa(child_sa_t *child_sa)
                    502: {
                    503:        return child_sa->get_mark(child_sa, TRUE).value &&
                    504:                   child_sa->get_mark(child_sa, FALSE).value;
                    505: }
                    506: 
                    507: METHOD(listener_t, child_updown, bool,
                    508:        private_forecast_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
                    509:        bool up)
                    510: {
                    511:        struct iptc_handle *ipth;
                    512:        host_t *lhost, *rhost;
                    513:        bool encap;
                    514: 
                    515:        lhost = ike_sa->get_my_host(ike_sa);
                    516:        rhost = ike_sa->get_other_host(ike_sa);
                    517:        encap = child_sa->has_encap(child_sa);
                    518: 
                    519:        if (handle_sa(child_sa))
                    520:        {
                    521:                ipth = init_handle();
                    522:                if (ipth)
                    523:                {
                    524:                        if (up)
                    525:                        {
                    526:                                if (add_entry(this, ipth, lhost, rhost, child_sa, encap))
                    527:                                {
                    528:                                        commit_handle(ipth);
                    529:                                }
                    530:                        }
                    531:                        else
                    532:                        {
                    533:                                if (remove_entry(this, ipth, child_sa))
                    534:                                {
                    535:                                        commit_handle(ipth);
                    536:                                }
                    537:                        }
                    538:                        iptc_free(ipth);
                    539:                }
                    540:        }
                    541:        return TRUE;
                    542: }
                    543: 
                    544: METHOD(listener_t, child_rekey, bool,
                    545:        private_forecast_listener_t *this, ike_sa_t *ike_sa,
                    546:        child_sa_t *old, child_sa_t *new)
                    547: {
                    548:        struct iptc_handle *ipth;;
                    549:        host_t *lhost, *rhost;
                    550: 
                    551:        lhost = ike_sa->get_my_host(ike_sa);
                    552:        rhost = ike_sa->get_other_host(ike_sa);
                    553: 
                    554:        if (handle_sa(old))
                    555:        {
                    556:                ipth = init_handle();
                    557:                if (ipth)
                    558:                {
                    559:                        if (remove_entry(this, ipth, old) &&
                    560:                                add_entry(this, ipth, lhost, rhost, new, new->has_encap(new)))
                    561:                        {
                    562:                                commit_handle(ipth);
                    563:                        }
                    564:                        iptc_free(ipth);
                    565:                }
                    566:        }
                    567:        return TRUE;
                    568: }
                    569: 
                    570: METHOD(listener_t, ike_update, bool,
                    571:        private_forecast_listener_t *this, ike_sa_t *ike_sa,
1.1.1.2 ! misho     572:        host_t *local, host_t *remote)
1.1       misho     573: {
                    574:        struct iptc_handle *ipth;
                    575:        enumerator_t *enumerator;
                    576:        child_sa_t *child_sa;
                    577:        bool encap;
                    578: 
                    579:        /* during ike_update(), has_encap() on the CHILD_SA has not yet been
                    580:         * updated, but shows the old state. */
                    581:        encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY);
                    582: 
                    583:        enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
                    584:        while (enumerator->enumerate(enumerator, &child_sa))
                    585:        {
                    586:                if (handle_sa(child_sa))
                    587:                {
                    588:                        ipth = init_handle();
                    589:                        if (ipth)
                    590:                        {
                    591:                                if (remove_entry(this, ipth, child_sa) &&
1.1.1.2 ! misho     592:                                        add_entry(this, ipth, local, remote, child_sa, encap))
1.1       misho     593:                                {
                    594:                                        commit_handle(ipth);
                    595:                                }
                    596:                                iptc_free(ipth);
                    597:                        }
                    598:                }
                    599:        }
                    600:        enumerator->destroy(enumerator);
                    601: 
                    602:        return TRUE;
                    603: }
                    604: 
                    605: CALLBACK(ts_filter, bool,
                    606:        entry_t *entry, enumerator_t *orig, va_list args)
                    607: {
                    608:        traffic_selector_t *ts, **out;
                    609:        uint32_t *mark;
                    610:        bool *reinject;
                    611: 
                    612:        VA_ARGS_VGET(args, out, mark, reinject);
                    613: 
                    614:        if (orig->enumerate(orig, &ts))
                    615:        {
                    616:                *out = ts;
                    617:                *mark = entry->mark;
                    618:                *reinject = entry->reinject;
                    619:                return TRUE;
                    620:        }
                    621:        return FALSE;
                    622: }
                    623: 
                    624: /**
                    625:  * Create inner enumerator over local traffic selectors
                    626:  */
                    627: static enumerator_t* create_inner_local(entry_t *entry, rwlock_t *lock)
                    628: {
                    629:        return enumerator_create_filter(array_create_enumerator(entry->lts),
                    630:                                                                        ts_filter, entry, NULL);
                    631: }
                    632: 
                    633: /**
                    634:  * Create inner enumerator over remote traffic selectors
                    635:  */
                    636: static enumerator_t* create_inner_remote(entry_t *entry, rwlock_t *lock)
                    637: {
                    638:        return enumerator_create_filter(array_create_enumerator(entry->rts),
                    639:                                                                        ts_filter, entry, NULL);
                    640: }
                    641: 
                    642: METHOD(forecast_listener_t, create_enumerator, enumerator_t*,
                    643:        private_forecast_listener_t *this, bool local)
                    644: {
                    645:        this->lock->read_lock(this->lock);
                    646:        return enumerator_create_nested(
                    647:                                        this->entries->create_enumerator(this->entries),
                    648:                                        (void*)(local ? create_inner_local : create_inner_remote),
                    649:                                        this->lock, (void*)this->lock->unlock);
                    650: }
                    651: 
                    652: METHOD(forecast_listener_t, set_broadcast, void,
                    653:        private_forecast_listener_t *this, host_t *bcast)
                    654: {
                    655:        if (bcast->get_family(bcast) == AF_INET)
                    656:        {
                    657:                struct sockaddr_in *in;
                    658: 
                    659:                in = (struct sockaddr_in*)bcast->get_sockaddr(bcast);
                    660:                this->broadcast = in->sin_addr.s_addr;
                    661:        }
                    662: }
                    663: 
                    664: METHOD(forecast_listener_t, destroy, void,
                    665:        private_forecast_listener_t *this)
                    666: {
                    667:        this->entries->destroy(this->entries);
                    668:        this->lock->destroy(this->lock);
                    669:        free(this);
                    670: }
                    671: 
                    672: /**
                    673:  * See header
                    674:  */
                    675: forecast_listener_t *forecast_listener_create()
                    676: {
                    677:        private_forecast_listener_t *this;
                    678: 
                    679:        INIT(this,
                    680:                .public = {
                    681:                        .listener = {
                    682:                                .ike_update = _ike_update,
                    683:                                .child_updown = _child_updown,
                    684:                                .child_rekey = _child_rekey,
                    685:                        },
                    686:                        .create_enumerator = _create_enumerator,
                    687:                        .set_broadcast = _set_broadcast,
                    688:                        .destroy = _destroy,
                    689:                },
                    690:                .entries = linked_list_create(),
                    691:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    692:                .reinject_configs = lib->settings->get_str(lib->settings,
                    693:                                                                "%s.plugins.forecast.reinject", "", lib->ns),
                    694:        );
                    695: 
                    696:        return &this->public;
                    697: }

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