Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2013 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include <unistd.h>
                     17: #include <fcntl.h>
                     18: 
                     19: #include "kernel_libipsec_router.h"
                     20: 
                     21: #include <daemon.h>
                     22: #include <ipsec.h>
                     23: #include <collections/hashtable.h>
                     24: #include <networking/tun_device.h>
                     25: #include <threading/rwlock.h>
                     26: #include <threading/thread.h>
                     27: #include <processing/jobs/callback_job.h>
                     28: 
                     29: typedef struct private_kernel_libipsec_router_t private_kernel_libipsec_router_t;
                     30: 
                     31: /**
                     32:  * Entry in the TUN device map
                     33:  */
                     34: typedef struct {
                     35:        /** virtual IP (points to internal data of tun) */
                     36:        host_t *addr;
                     37:        /** underlying TUN file descriptor (cached from tun) */
                     38:        int fd;
                     39:        /** TUN device */
                     40:        tun_device_t *tun;
                     41: } tun_entry_t;
                     42: 
                     43: /**
                     44:  * Single instance of the router
                     45:  */
                     46: kernel_libipsec_router_t *router;
                     47: 
                     48: /**
                     49:  * Private data
                     50:  */
                     51: struct private_kernel_libipsec_router_t {
                     52: 
                     53:        /**
                     54:         * Public interface
                     55:         */
                     56:        kernel_libipsec_router_t public;
                     57: 
                     58:        /**
                     59:         * Default TUN device if kernel interface does not require separate TUN
                     60:         * devices per VIP or for tunnels without VIP.
                     61:         */
                     62:        tun_entry_t tun;
                     63: 
                     64:        /**
                     65:         * Hashtable that maps virtual IPs to TUN devices (tun_entry_t).
                     66:         */
                     67:        hashtable_t *tuns;
                     68: 
                     69:        /**
                     70:         * Lock for TUN device map
                     71:         */
                     72:        rwlock_t *lock;
                     73: 
                     74:        /**
                     75:         * Pipe to signal handle_plain() about changes regarding TUN devices
                     76:         */
                     77:        int notify[2];
                     78: };
                     79: 
                     80: /**
                     81:  * Hash function for TUN device map
                     82:  */
                     83: static u_int tun_entry_hash(tun_entry_t *entry)
                     84: {
                     85:        return chunk_hash(entry->addr->get_address(entry->addr));
                     86: }
                     87: 
                     88: /**
                     89:  * Comparison function for TUN device map
                     90:  */
                     91: static bool tun_entry_equals(tun_entry_t *a, tun_entry_t *b)
                     92: {
                     93:        return a->addr->ip_equals(a->addr, b->addr);
                     94: }
                     95: 
                     96: /**
                     97:  * Outbound callback
                     98:  */
                     99: static void send_esp(void *data, esp_packet_t *packet)
                    100: {
                    101:        charon->sender->send_no_marker(charon->sender, (packet_t*)packet);
                    102: }
                    103: 
                    104: /**
                    105:  * Receiver callback
                    106:  */
                    107: static void receiver_esp_cb(void *data, packet_t *packet)
                    108: {
                    109:        ipsec->processor->queue_inbound(ipsec->processor,
                    110:                                                                        esp_packet_create_from_packet(packet));
                    111: }
                    112: 
                    113: /**
                    114:  * Inbound callback
                    115:  */
                    116: static void deliver_plain(private_kernel_libipsec_router_t *this,
                    117:                                                  ip_packet_t *packet)
                    118: {
                    119:        tun_device_t *tun;
                    120:        tun_entry_t *entry, lookup = {
                    121:                .addr = packet->get_destination(packet),
                    122:        };
                    123: 
                    124:        this->lock->read_lock(this->lock);
                    125:        entry = this->tuns->get(this->tuns, &lookup);
                    126:        tun = entry ? entry->tun : this->tun.tun;
                    127:        tun->write_packet(tun, packet->get_encoding(packet));
                    128:        this->lock->unlock(this->lock);
                    129:        packet->destroy(packet);
                    130: }
                    131: 
                    132: /**
                    133:  * Read and process outbound plaintext packet for the given TUN device
                    134:  */
                    135: static void process_plain(tun_device_t *tun)
                    136: {
                    137:        chunk_t raw;
                    138: 
                    139:        if (tun->read_packet(tun, &raw))
                    140:        {
                    141:                ip_packet_t *packet;
                    142: 
                    143:                packet = ip_packet_create(raw);
                    144:                if (packet)
                    145:                {
                    146:                        ipsec->processor->queue_outbound(ipsec->processor, packet);
                    147:                }
                    148:                else
                    149:                {
                    150:                        DBG1(DBG_KNL, "invalid IP packet read from TUN device");
                    151:                }
                    152:        }
                    153: }
                    154: 
                    155: /**
                    156:  * Find flagged revents in a pollfd set by fd
                    157:  */
                    158: static int find_revents(struct pollfd *pfd, int count, int fd)
                    159: {
                    160:        int i;
                    161: 
                    162:        for (i = 0; i < count; i++)
                    163:        {
                    164:                if (pfd[i].fd == fd)
                    165:                {
                    166:                        return pfd[i].revents;
                    167:                }
                    168:        }
                    169:        return 0;
                    170: }
                    171: 
                    172: /**
                    173:  * Job handling outbound plaintext packets
                    174:  */
                    175: static job_requeue_t handle_plain(private_kernel_libipsec_router_t *this)
                    176: {
                    177:        enumerator_t *enumerator;
                    178:        tun_entry_t *entry;
                    179:        bool oldstate;
                    180:        int count = 0;
                    181:        char buf[1];
                    182:        struct pollfd *pfd;
                    183: 
                    184:        this->lock->read_lock(this->lock);
                    185: 
                    186:        pfd = alloca(sizeof(*pfd) * (this->tuns->get_count(this->tuns) + 2));
                    187:        pfd[count].fd = this->notify[0];
                    188:        pfd[count].events = POLLIN;
                    189:        count++;
                    190:        pfd[count].fd = this->tun.fd;
                    191:        pfd[count].events = POLLIN;
                    192:        count++;
                    193: 
                    194:        enumerator = this->tuns->create_enumerator(this->tuns);
                    195:        while (enumerator->enumerate(enumerator, NULL, &entry))
                    196:        {
                    197:                pfd[count].fd = entry->fd;
                    198:                pfd[count].events = POLLIN;
                    199:                count++;
                    200:        }
                    201:        enumerator->destroy(enumerator);
                    202:        this->lock->unlock(this->lock);
                    203: 
                    204:        oldstate = thread_cancelability(TRUE);
                    205:        if (poll(pfd, count, -1) <= 0)
                    206:        {
                    207:                thread_cancelability(oldstate);
                    208:                return JOB_REQUEUE_FAIR;
                    209:        }
                    210:        thread_cancelability(oldstate);
                    211: 
                    212:        if (pfd[0].revents & POLLIN)
                    213:        {
                    214:                /* list of TUN devices changed, read notification data, rebuild FDs */
                    215:                while (read(this->notify[0], &buf, sizeof(buf)) == sizeof(buf))
                    216:                {
                    217:                        /* nop */
                    218:                }
                    219:                return JOB_REQUEUE_DIRECT;
                    220:        }
                    221: 
                    222:        if (pfd[1].revents & POLLIN)
                    223:        {
                    224:                process_plain(this->tun.tun);
                    225:        }
                    226: 
                    227:        this->lock->read_lock(this->lock);
                    228:        enumerator = this->tuns->create_enumerator(this->tuns);
                    229:        while (enumerator->enumerate(enumerator, NULL, &entry))
                    230:        {
                    231:                if (find_revents(pfd, count, entry->fd) & POLLIN)
                    232:                {
                    233:                        process_plain(entry->tun);
                    234:                }
                    235:        }
                    236:        enumerator->destroy(enumerator);
                    237:        this->lock->unlock(this->lock);
                    238: 
                    239:        return JOB_REQUEUE_DIRECT;
                    240: }
                    241: 
                    242: METHOD(kernel_listener_t, tun, bool,
                    243:        private_kernel_libipsec_router_t *this, tun_device_t *tun, bool created)
                    244: {
                    245:        tun_entry_t *entry, lookup;
                    246:        char buf[] = {0x01};
                    247: 
                    248:        this->lock->write_lock(this->lock);
                    249:        if (created)
                    250:        {
                    251:                INIT(entry,
                    252:                        .addr = tun->get_address(tun, NULL),
                    253:                        .fd = tun->get_fd(tun),
                    254:                        .tun = tun,
                    255:                );
                    256:                this->tuns->put(this->tuns, entry, entry);
                    257:        }
                    258:        else
                    259:        {
                    260:                lookup.addr = tun->get_address(tun, NULL);
                    261:                entry = this->tuns->remove(this->tuns, &lookup);
                    262:                free(entry);
                    263:        }
                    264:        /* notify handler thread to recreate FD set */
                    265:        ignore_result(write(this->notify[1], buf, sizeof(buf)));
                    266:        this->lock->unlock(this->lock);
                    267:        return TRUE;
                    268: }
                    269: 
                    270: METHOD(kernel_libipsec_router_t, get_tun_name, char*,
                    271:        private_kernel_libipsec_router_t *this, host_t *vip)
                    272: {
                    273:        tun_entry_t *entry, lookup = {
                    274:                .addr = vip,
                    275:        };
                    276:        tun_device_t *tun;
                    277:        char *name;
                    278: 
                    279:        if (!vip)
                    280:        {
                    281:                return strdup(this->tun.tun->get_name(this->tun.tun));
                    282:        }
                    283:        this->lock->read_lock(this->lock);
                    284:        entry = this->tuns->get(this->tuns, &lookup);
                    285:        tun = entry ? entry->tun : this->tun.tun;
                    286:        name = strdup(tun->get_name(tun));
                    287:        this->lock->unlock(this->lock);
                    288:        return name;
                    289: }
                    290: 
                    291: METHOD(kernel_libipsec_router_t, destroy, void,
                    292:        private_kernel_libipsec_router_t *this)
                    293: {
                    294:        charon->receiver->del_esp_cb(charon->receiver,
                    295:                                                                (receiver_esp_cb_t)receiver_esp_cb);
                    296:        ipsec->processor->unregister_outbound(ipsec->processor,
                    297:                                                                                 (ipsec_outbound_cb_t)send_esp);
                    298:        ipsec->processor->unregister_inbound(ipsec->processor,
                    299:                                                                                 (ipsec_inbound_cb_t)deliver_plain);
                    300:        charon->kernel->remove_listener(charon->kernel, &this->public.listener);
                    301:        this->lock->destroy(this->lock);
                    302:        this->tuns->destroy(this->tuns);
                    303:        close(this->notify[0]);
                    304:        close(this->notify[1]);
                    305:        router = NULL;
                    306:        free(this);
                    307: }
                    308: 
                    309: /**
                    310:  * Set O_NONBLOCK on the given socket.
                    311:  */
                    312: static bool set_nonblock(int socket)
                    313: {
                    314:        int flags = fcntl(socket, F_GETFL);
                    315:        return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1;
                    316: }
                    317: 
                    318: /*
                    319:  * See header file
                    320:  */
                    321: kernel_libipsec_router_t *kernel_libipsec_router_create()
                    322: {
                    323:        private_kernel_libipsec_router_t *this;
                    324: 
                    325:        INIT(this,
                    326:                .public = {
                    327:                        .listener = {
                    328:                                .tun = _tun,
                    329:                        },
                    330:                        .get_tun_name = _get_tun_name,
                    331:                        .destroy = _destroy,
                    332:                },
                    333:                .tun = {
                    334:                        .tun = lib->get(lib, "kernel-libipsec-tun"),
                    335:                }
                    336:        );
                    337: 
                    338:        if (pipe(this->notify) != 0 ||
                    339:                !set_nonblock(this->notify[0]) || !set_nonblock(this->notify[1]))
                    340:        {
                    341:                DBG1(DBG_KNL, "creating notify pipe for kernel-libipsec router failed");
                    342:                free(this);
                    343:                return NULL;
                    344:        }
                    345: 
                    346:        this->tun.fd = this->tun.tun->get_fd(this->tun.tun);
                    347: 
                    348:        this->tuns = hashtable_create((hashtable_hash_t)tun_entry_hash,
                    349:                                                                  (hashtable_equals_t)tun_entry_equals, 4);
                    350:        this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
                    351: 
                    352:        charon->kernel->add_listener(charon->kernel, &this->public.listener);
                    353:        ipsec->processor->register_outbound(ipsec->processor, send_esp, NULL);
                    354:        ipsec->processor->register_inbound(ipsec->processor,
                    355:                                                                        (ipsec_inbound_cb_t)deliver_plain, this);
                    356:        charon->receiver->add_esp_cb(charon->receiver,
                    357:                                                                        (receiver_esp_cb_t)receiver_esp_cb, NULL);
                    358:        lib->processor->queue_job(lib->processor,
                    359:                        (job_t*)callback_job_create((callback_job_cb_t)handle_plain, this,
                    360:                                                                        NULL, (callback_job_cancel_t)return_false));
                    361: 
                    362:        router = &this->public;
                    363:        return &this->public;
                    364: }

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