Return to kernel_libipsec_router.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / kernel_libipsec |
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: }