Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2018 Tobias Brunner
! 3: * Copyright (C) 2008 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16: /*
! 17: * Copyright (C) 2014 Nanoteq Pty Ltd
! 18: *
! 19: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 20: * of this software and associated documentation files (the "Software"), to deal
! 21: * in the Software without restriction, including without limitation the rights
! 22: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 23: * copies of the Software, and to permit persons to whom the Software is
! 24: * furnished to do so, subject to the following conditions:
! 25: *
! 26: * The above copyright notice and this permission notice shall be included in
! 27: * all copies or substantial portions of the Software.
! 28: *
! 29: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 30: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 31: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 32: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 33: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 34: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 35: * THE SOFTWARE.
! 36: */
! 37:
! 38: #include <stdint.h>
! 39: #include <sys/types.h>
! 40: #include <sys/socket.h>
! 41:
! 42: #ifdef __FreeBSD__
! 43: #include <limits.h> /* for LONG_MAX */
! 44: #endif
! 45:
! 46: #ifdef HAVE_NET_PFKEYV2_H
! 47: #include <net/pfkeyv2.h>
! 48: #else
! 49: #include <linux/pfkeyv2.h>
! 50: #endif
! 51:
! 52: #ifdef SADB_X_EXT_NAT_T_TYPE
! 53: #define HAVE_NATT
! 54: #endif
! 55:
! 56: #ifdef HAVE_NETIPSEC_IPSEC_H
! 57: #include <netipsec/ipsec.h>
! 58: #elif defined(HAVE_NETINET6_IPSEC_H)
! 59: #include <netinet6/ipsec.h>
! 60: #else
! 61: #include <linux/ipsec.h>
! 62: #endif
! 63:
! 64: #ifdef HAVE_NATT
! 65: #ifdef HAVE_LINUX_UDP_H
! 66: #include <linux/udp.h>
! 67: #else
! 68: #include <netinet/udp.h>
! 69: #endif /*HAVE_LINUX_UDP_H*/
! 70: #endif /*HAVE_NATT*/
! 71:
! 72: #include <unistd.h>
! 73: #include <time.h>
! 74: #include <errno.h>
! 75: #ifdef __APPLE__
! 76: #include <sys/sysctl.h>
! 77: #endif
! 78:
! 79: #include "kernel_pfkey_ipsec.h"
! 80:
! 81: #include <daemon.h>
! 82: #include <utils/debug.h>
! 83: #include <networking/host.h>
! 84: #include <collections/linked_list.h>
! 85: #include <collections/hashtable.h>
! 86: #include <threading/mutex.h>
! 87:
! 88: /** non linux specific */
! 89: #ifndef IPPROTO_COMP
! 90: #ifdef IPPROTO_IPCOMP
! 91: #define IPPROTO_COMP IPPROTO_IPCOMP
! 92: #endif
! 93: #endif
! 94:
! 95: #ifndef SADB_X_AALG_SHA2_256HMAC
! 96: #define SADB_X_AALG_SHA2_256HMAC SADB_X_AALG_SHA2_256
! 97: #define SADB_X_AALG_SHA2_384HMAC SADB_X_AALG_SHA2_384
! 98: #define SADB_X_AALG_SHA2_512HMAC SADB_X_AALG_SHA2_512
! 99: #endif
! 100:
! 101: #ifndef SADB_X_EALG_AESCBC
! 102: #define SADB_X_EALG_AESCBC SADB_X_EALG_AES
! 103: #endif
! 104:
! 105: #ifndef SADB_X_EALG_CASTCBC
! 106: #define SADB_X_EALG_CASTCBC SADB_X_EALG_CAST128CBC
! 107: #endif
! 108:
! 109: #if !defined(SADB_X_EALG_AES_GCM_ICV8) && defined(SADB_X_EALG_AESGCM8)
! 110: #define SADB_X_EALG_AES_GCM_ICV8 SADB_X_EALG_AESGCM8
! 111: #define SADB_X_EALG_AES_GCM_ICV12 SADB_X_EALG_AESGCM12
! 112: #define SADB_X_EALG_AES_GCM_ICV16 SADB_X_EALG_AESGCM16
! 113: #endif
! 114:
! 115: #ifndef SOL_IP
! 116: #define SOL_IP IPPROTO_IP
! 117: #define SOL_IPV6 IPPROTO_IPV6
! 118: #endif
! 119:
! 120: /** from linux/in.h */
! 121: #ifndef IP_IPSEC_POLICY
! 122: #define IP_IPSEC_POLICY 16
! 123: #endif
! 124:
! 125: /** missing on uclibc */
! 126: #ifndef IPV6_IPSEC_POLICY
! 127: #define IPV6_IPSEC_POLICY 34
! 128: #endif
! 129:
! 130: /* from linux/udp.h */
! 131: #ifndef UDP_ENCAP
! 132: #define UDP_ENCAP 100
! 133: #endif
! 134:
! 135: #ifndef UDP_ENCAP_ESPINUDP
! 136: #define UDP_ENCAP_ESPINUDP 2
! 137: #endif
! 138:
! 139: /* this is not defined on some platforms */
! 140: #ifndef SOL_UDP
! 141: #define SOL_UDP IPPROTO_UDP
! 142: #endif
! 143:
! 144: /** Base priority for installed policies */
! 145: #define PRIO_BASE 200000
! 146:
! 147: #ifdef __APPLE__
! 148: /** from xnu/bsd/net/pfkeyv2.h */
! 149: #define SADB_X_EXT_NATT 0x002
! 150: struct sadb_sa_2 {
! 151: struct sadb_sa sa;
! 152: uint16_t sadb_sa_natt_port;
! 153: uint16_t sadb_reserved0;
! 154: uint32_t sadb_reserved1;
! 155: };
! 156: #endif
! 157:
! 158: /** buffer size for PF_KEY messages */
! 159: #define PFKEY_BUFFER_SIZE 4096
! 160:
! 161: /** PF_KEY messages are 64 bit aligned */
! 162: #define PFKEY_ALIGNMENT 8
! 163: /** aligns len to 64 bits */
! 164: #define PFKEY_ALIGN(len) (((len) + PFKEY_ALIGNMENT - 1) & ~(PFKEY_ALIGNMENT - 1))
! 165: /** calculates the properly padded length in 64 bit chunks */
! 166: #define PFKEY_LEN(len) ((PFKEY_ALIGN(len) / PFKEY_ALIGNMENT))
! 167: /** calculates user mode length i.e. in bytes */
! 168: #define PFKEY_USER_LEN(len) ((len) * PFKEY_ALIGNMENT)
! 169:
! 170: /** given a PF_KEY message header and an extension this updates the length in the header */
! 171: #define PFKEY_EXT_ADD(msg, ext) ((msg)->sadb_msg_len += ((struct sadb_ext*)ext)->sadb_ext_len)
! 172: /** given a PF_KEY message header this returns a pointer to the next extension */
! 173: #define PFKEY_EXT_ADD_NEXT(msg) ((struct sadb_ext*)(((char*)(msg)) + PFKEY_USER_LEN((msg)->sadb_msg_len)))
! 174: /** copy an extension and append it to a PF_KEY message */
! 175: #define PFKEY_EXT_COPY(msg, ext) (PFKEY_EXT_ADD(msg, memcpy(PFKEY_EXT_ADD_NEXT(msg), ext, PFKEY_USER_LEN(((struct sadb_ext*)ext)->sadb_ext_len))))
! 176: /** given a PF_KEY extension this returns a pointer to the next extension */
! 177: #define PFKEY_EXT_NEXT(ext) ((struct sadb_ext*)(((char*)(ext)) + PFKEY_USER_LEN(((struct sadb_ext*)ext)->sadb_ext_len)))
! 178: /** given a PF_KEY extension this returns a pointer to the next extension also updates len (len in 64 bit words) */
! 179: #define PFKEY_EXT_NEXT_LEN(ext,len) ((len) -= (ext)->sadb_ext_len, PFKEY_EXT_NEXT(ext))
! 180: /** true if ext has a valid length and len is large enough to contain ext (assuming len in 64 bit words) */
! 181: #define PFKEY_EXT_OK(ext,len) ((len) >= PFKEY_LEN(sizeof(struct sadb_ext)) && \
! 182: (ext)->sadb_ext_len >= PFKEY_LEN(sizeof(struct sadb_ext)) && \
! 183: (ext)->sadb_ext_len <= (len))
! 184:
! 185: typedef struct private_kernel_pfkey_ipsec_t private_kernel_pfkey_ipsec_t;
! 186:
! 187: /**
! 188: * Private variables and functions of kernel_pfkey class.
! 189: */
! 190: struct private_kernel_pfkey_ipsec_t
! 191: {
! 192: /**
! 193: * Public part of the kernel_pfkey_t object.
! 194: */
! 195: kernel_pfkey_ipsec_t public;
! 196:
! 197: /**
! 198: * mutex to lock access to various lists
! 199: */
! 200: mutex_t *mutex;
! 201:
! 202: /**
! 203: * List of installed policies (policy_entry_t)
! 204: */
! 205: linked_list_t *policies;
! 206:
! 207: /**
! 208: * List of exclude routes (exclude_route_t)
! 209: */
! 210: linked_list_t *excludes;
! 211:
! 212: /**
! 213: * Hash table of IPsec SAs using policies (ipsec_sa_t)
! 214: */
! 215: hashtable_t *sas;
! 216:
! 217: /**
! 218: * whether to install routes along policies
! 219: */
! 220: bool install_routes;
! 221:
! 222: /**
! 223: * whether to install the route via internal interface
! 224: */
! 225: bool route_via_internal;
! 226:
! 227: /**
! 228: * mutex to lock access to the PF_KEY socket
! 229: */
! 230: mutex_t *mutex_pfkey;
! 231:
! 232: /**
! 233: * PF_KEY socket to communicate with the kernel
! 234: */
! 235: int socket;
! 236:
! 237: /**
! 238: * PF_KEY socket to receive acquire and expire events
! 239: */
! 240: int socket_events;
! 241:
! 242: /**
! 243: * sequence number for messages sent to the kernel
! 244: */
! 245: int seq;
! 246: };
! 247:
! 248: typedef struct exclude_route_t exclude_route_t;
! 249:
! 250: /**
! 251: * Exclude route definition
! 252: */
! 253: struct exclude_route_t {
! 254: /** destination address of exclude */
! 255: host_t *dst;
! 256: /** source address for route */
! 257: host_t *src;
! 258: /** nexthop exclude has been installed */
! 259: host_t *gtw;
! 260: /** references to this route */
! 261: int refs;
! 262: };
! 263:
! 264: /**
! 265: * clean up a route exclude entry
! 266: */
! 267: static void exclude_route_destroy(exclude_route_t *this)
! 268: {
! 269: this->dst->destroy(this->dst);
! 270: this->src->destroy(this->src);
! 271: this->gtw->destroy(this->gtw);
! 272: free(this);
! 273: }
! 274:
! 275: typedef struct route_entry_t route_entry_t;
! 276:
! 277: /**
! 278: * installed routing entry
! 279: */
! 280: struct route_entry_t {
! 281: /** name of the interface the route is bound to */
! 282: char *if_name;
! 283:
! 284: /** source ip of the route */
! 285: host_t *src_ip;
! 286:
! 287: /** gateway for this route */
! 288: host_t *gateway;
! 289:
! 290: /** destination net */
! 291: chunk_t dst_net;
! 292:
! 293: /** destination net prefixlen */
! 294: uint8_t prefixlen;
! 295:
! 296: /** reference to exclude route, if any */
! 297: exclude_route_t *exclude;
! 298: };
! 299:
! 300: /**
! 301: * destroy an route_entry_t object
! 302: */
! 303: static void route_entry_destroy(route_entry_t *this)
! 304: {
! 305: free(this->if_name);
! 306: DESTROY_IF(this->src_ip);
! 307: DESTROY_IF(this->gateway);
! 308: chunk_free(&this->dst_net);
! 309: free(this);
! 310: }
! 311:
! 312: /**
! 313: * compare two route_entry_t objects
! 314: */
! 315: static bool route_entry_equals(route_entry_t *a, route_entry_t *b)
! 316: {
! 317: return a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
! 318: a->src_ip->ip_equals(a->src_ip, b->src_ip) &&
! 319: a->gateway && b->gateway &&
! 320: a->gateway->ip_equals(a->gateway, b->gateway) &&
! 321: chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen;
! 322: }
! 323:
! 324: typedef struct ipsec_sa_t ipsec_sa_t;
! 325:
! 326: /**
! 327: * IPsec SA assigned to a policy.
! 328: */
! 329: struct ipsec_sa_t {
! 330: /** Source address of this SA */
! 331: host_t *src;
! 332:
! 333: /** Destination address of this SA */
! 334: host_t *dst;
! 335:
! 336: /** Description of this SA */
! 337: ipsec_sa_cfg_t cfg;
! 338:
! 339: /** Reference count for this SA */
! 340: refcount_t refcount;
! 341: };
! 342:
! 343: /**
! 344: * Hash function for ipsec_sa_t objects
! 345: */
! 346: static u_int ipsec_sa_hash(ipsec_sa_t *sa)
! 347: {
! 348: return chunk_hash_inc(sa->src->get_address(sa->src),
! 349: chunk_hash_inc(sa->dst->get_address(sa->dst),
! 350: chunk_hash(chunk_from_thing(sa->cfg))));
! 351: }
! 352:
! 353: /**
! 354: * Equality function for ipsec_sa_t objects
! 355: */
! 356: static bool ipsec_sa_equals(ipsec_sa_t *sa, ipsec_sa_t *other_sa)
! 357: {
! 358: return sa->src->ip_equals(sa->src, other_sa->src) &&
! 359: sa->dst->ip_equals(sa->dst, other_sa->dst) &&
! 360: ipsec_sa_cfg_equals(&sa->cfg, &other_sa->cfg);
! 361: }
! 362:
! 363: /**
! 364: * Allocate or reference an IPsec SA object
! 365: */
! 366: static ipsec_sa_t *ipsec_sa_create(private_kernel_pfkey_ipsec_t *this,
! 367: host_t *src, host_t *dst,
! 368: ipsec_sa_cfg_t *cfg)
! 369: {
! 370: ipsec_sa_t *sa, *found;
! 371: INIT(sa,
! 372: .src = src,
! 373: .dst = dst,
! 374: .cfg = *cfg,
! 375: );
! 376: found = this->sas->get(this->sas, sa);
! 377: if (!found)
! 378: {
! 379: sa->src = src->clone(src);
! 380: sa->dst = dst->clone(dst);
! 381: this->sas->put(this->sas, sa, sa);
! 382: }
! 383: else
! 384: {
! 385: free(sa);
! 386: sa = found;
! 387: }
! 388: ref_get(&sa->refcount);
! 389: return sa;
! 390: }
! 391:
! 392: /**
! 393: * Release and destroy an IPsec SA object
! 394: */
! 395: static void ipsec_sa_destroy(private_kernel_pfkey_ipsec_t *this,
! 396: ipsec_sa_t *sa)
! 397: {
! 398: if (ref_put(&sa->refcount))
! 399: {
! 400: this->sas->remove(this->sas, sa);
! 401: DESTROY_IF(sa->src);
! 402: DESTROY_IF(sa->dst);
! 403: free(sa);
! 404: }
! 405: }
! 406:
! 407: typedef struct policy_sa_t policy_sa_t;
! 408: typedef struct policy_sa_out_t policy_sa_out_t;
! 409:
! 410: /**
! 411: * Mapping between a policy and an IPsec SA.
! 412: */
! 413: struct policy_sa_t {
! 414: /** Priority assigned to the policy when installed with this SA */
! 415: uint32_t priority;
! 416:
! 417: /** Base priority assigned to the policy when installed with this SA */
! 418: uint32_t auto_priority;
! 419:
! 420: /** Type of the policy */
! 421: policy_type_t type;
! 422:
! 423: /** Assigned SA */
! 424: ipsec_sa_t *sa;
! 425: };
! 426:
! 427: /**
! 428: * For outbound policies we also cache the traffic selectors in order to install
! 429: * the route.
! 430: */
! 431: struct policy_sa_out_t {
! 432: /** Generic interface */
! 433: policy_sa_t generic;
! 434:
! 435: /** Source traffic selector of this policy */
! 436: traffic_selector_t *src_ts;
! 437:
! 438: /** Destination traffic selector of this policy */
! 439: traffic_selector_t *dst_ts;
! 440: };
! 441:
! 442: /**
! 443: * Create a policy_sa(_in)_t object
! 444: */
! 445: static policy_sa_t *policy_sa_create(private_kernel_pfkey_ipsec_t *this,
! 446: policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst,
! 447: traffic_selector_t *src_ts, traffic_selector_t *dst_ts, ipsec_sa_cfg_t *cfg)
! 448: {
! 449: policy_sa_t *policy;
! 450:
! 451: if (dir == POLICY_OUT)
! 452: {
! 453: policy_sa_out_t *out;
! 454: INIT(out,
! 455: .src_ts = src_ts->clone(src_ts),
! 456: .dst_ts = dst_ts->clone(dst_ts),
! 457: );
! 458: policy = &out->generic;
! 459: }
! 460: else
! 461: {
! 462: INIT(policy, .priority = 0);
! 463: }
! 464: policy->type = type;
! 465: policy->sa = ipsec_sa_create(this, src, dst, cfg);
! 466: return policy;
! 467: }
! 468:
! 469: /**
! 470: * Destroy a policy_sa(_in)_t object
! 471: */
! 472: static void policy_sa_destroy(policy_sa_t *policy, policy_dir_t dir,
! 473: private_kernel_pfkey_ipsec_t *this)
! 474: {
! 475: if (dir == POLICY_OUT)
! 476: {
! 477: policy_sa_out_t *out = (policy_sa_out_t*)policy;
! 478: out->src_ts->destroy(out->src_ts);
! 479: out->dst_ts->destroy(out->dst_ts);
! 480: }
! 481: ipsec_sa_destroy(this, policy->sa);
! 482: free(policy);
! 483: }
! 484:
! 485: CALLBACK(policy_sa_destroy_cb, void,
! 486: policy_sa_t *policy, va_list args)
! 487: {
! 488: private_kernel_pfkey_ipsec_t *this;
! 489: policy_dir_t dir;
! 490:
! 491: VA_ARGS_VGET(args, dir, this);
! 492: policy_sa_destroy(policy, dir, this);
! 493: }
! 494:
! 495: typedef struct policy_entry_t policy_entry_t;
! 496:
! 497: /**
! 498: * installed kernel policy.
! 499: */
! 500: struct policy_entry_t {
! 501: /** Index assigned by the kernel */
! 502: uint32_t index;
! 503:
! 504: /** Direction of this policy: in, out, forward */
! 505: uint8_t direction;
! 506:
! 507: /** Parameters of installed policy */
! 508: struct {
! 509: /** Subnet and port */
! 510: host_t *net;
! 511: /** Subnet mask */
! 512: uint8_t mask;
! 513: /** Protocol */
! 514: uint8_t proto;
! 515: } src, dst;
! 516:
! 517: /** Associated route installed for this policy */
! 518: route_entry_t *route;
! 519:
! 520: /** List of SAs this policy is used by, ordered by priority */
! 521: linked_list_t *used_by;
! 522: };
! 523:
! 524: /**
! 525: * Create a policy_entry_t object
! 526: */
! 527: static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts,
! 528: traffic_selector_t *dst_ts,
! 529: policy_dir_t dir)
! 530: {
! 531: policy_entry_t *policy;
! 532: INIT(policy,
! 533: .direction = dir,
! 534: );
! 535: uint16_t port;
! 536: uint8_t proto;
! 537:
! 538: src_ts->to_subnet(src_ts, &policy->src.net, &policy->src.mask);
! 539: dst_ts->to_subnet(dst_ts, &policy->dst.net, &policy->dst.mask);
! 540:
! 541: /* src or dest proto may be "any" (0), use more restrictive one */
! 542: proto = max(src_ts->get_protocol(src_ts), dst_ts->get_protocol(dst_ts));
! 543: /* map the ports to ICMP type/code how the Linux kernel expects them, that
! 544: * is, type in src, code in dst */
! 545: if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)
! 546: {
! 547: port = max(policy->src.net->get_port(policy->src.net),
! 548: policy->dst.net->get_port(policy->dst.net));
! 549: policy->src.net->set_port(policy->src.net,
! 550: traffic_selector_icmp_type(port));
! 551: policy->dst.net->set_port(policy->dst.net,
! 552: traffic_selector_icmp_code(port));
! 553: }
! 554: else if (!proto)
! 555: {
! 556: proto = IPSEC_PROTO_ANY;
! 557: }
! 558: policy->src.proto = policy->dst.proto = proto;
! 559:
! 560: return policy;
! 561: }
! 562:
! 563: /**
! 564: * Destroy a policy_entry_t object
! 565: */
! 566: static void policy_entry_destroy(policy_entry_t *policy,
! 567: private_kernel_pfkey_ipsec_t *this)
! 568: {
! 569: if (policy->route)
! 570: {
! 571: route_entry_destroy(policy->route);
! 572: }
! 573: if (policy->used_by)
! 574: {
! 575: policy->used_by->invoke_function(policy->used_by, policy_sa_destroy_cb,
! 576: policy->direction, this);
! 577: policy->used_by->destroy(policy->used_by);
! 578: }
! 579: DESTROY_IF(policy->src.net);
! 580: DESTROY_IF(policy->dst.net);
! 581: free(policy);
! 582: }
! 583:
! 584: CALLBACK(policy_entry_destroy_cb, void,
! 585: policy_entry_t *policy, va_list args)
! 586: {
! 587: private_kernel_pfkey_ipsec_t *this;
! 588:
! 589: VA_ARGS_VGET(args, this);
! 590: policy_entry_destroy(policy, this);
! 591: }
! 592:
! 593: CALLBACK(policy_entry_equals, bool,
! 594: policy_entry_t *current, va_list args)
! 595: {
! 596: policy_entry_t *policy;
! 597:
! 598: VA_ARGS_VGET(args, policy);
! 599: return current->direction == policy->direction &&
! 600: current->src.proto == policy->src.proto &&
! 601: current->dst.proto == policy->dst.proto &&
! 602: current->src.mask == policy->src.mask &&
! 603: current->dst.mask == policy->dst.mask &&
! 604: current->src.net->equals(current->src.net, policy->src.net) &&
! 605: current->dst.net->equals(current->dst.net, policy->dst.net);
! 606: }
! 607:
! 608: CALLBACK(policy_entry_match_byindex, bool,
! 609: policy_entry_t *current, va_list args)
! 610: {
! 611: uint32_t index;
! 612:
! 613: VA_ARGS_VGET(args, index);
! 614: return current->index == index;
! 615: }
! 616:
! 617: /**
! 618: * Calculate the priority of a policy
! 619: *
! 620: * This is the same formula we use in the kernel-netlink interface, but some
! 621: * features are currently not or only partially supported by PF_KEY.
! 622: *
! 623: * bits 0-0: separate trap and regular policies (0..1) 1 bit
! 624: * bits 1-1: reserved for interface restriction (0..1) 1 bit
! 625: * bits 2-7: src + dst port mask bits (2 * 0..16) 6 bits
! 626: * bits 8-8: restriction to protocol (0..1) 1 bit
! 627: * bits 9-17: src + dst network mask bits (2 * 0..128) 9 bits
! 628: * 18 bits
! 629: *
! 630: * smallest value: 000000000 0 000000 0 0: 0, lowest priority = 100'000
! 631: * largest value : 100000000 1 100000 0 1: 131'457, highst priority = 68'543
! 632: */
! 633: static inline uint32_t get_priority(policy_entry_t *policy,
! 634: policy_priority_t prio)
! 635: {
! 636: uint32_t priority = PRIO_BASE;
! 637:
! 638: switch (prio)
! 639: {
! 640: case POLICY_PRIORITY_FALLBACK:
! 641: priority += PRIO_BASE;
! 642: /* fall-through */
! 643: case POLICY_PRIORITY_ROUTED:
! 644: case POLICY_PRIORITY_DEFAULT:
! 645: priority += PRIO_BASE;
! 646: /* fall-through */
! 647: case POLICY_PRIORITY_PASS:
! 648: break;
! 649: }
! 650:
! 651: /* calculate priority */
! 652: priority -= (policy->src.mask + policy->dst.mask) * 512;
! 653: priority -= policy->src.proto != IPSEC_PROTO_ANY ? 256 : 0;
! 654: priority -= policy->src.net->get_port(policy->src.net) ? 64 : 0;
! 655: priority -= policy->dst.net->get_port(policy->dst.net) ? 64 : 0;
! 656: priority -= (prio != POLICY_PRIORITY_ROUTED);
! 657: return priority;
! 658: }
! 659:
! 660: typedef struct pfkey_msg_t pfkey_msg_t;
! 661:
! 662: struct pfkey_msg_t
! 663: {
! 664: /**
! 665: * PF_KEY message base
! 666: */
! 667: struct sadb_msg *msg;
! 668:
! 669: /**
! 670: * PF_KEY message extensions
! 671: */
! 672: union {
! 673: struct sadb_ext *ext[SADB_EXT_MAX + 1];
! 674: struct {
! 675: struct sadb_ext *reserved; /* SADB_EXT_RESERVED */
! 676: struct sadb_sa *sa; /* SADB_EXT_SA */
! 677: struct sadb_lifetime *lft_current; /* SADB_EXT_LIFETIME_CURRENT */
! 678: struct sadb_lifetime *lft_hard; /* SADB_EXT_LIFETIME_HARD */
! 679: struct sadb_lifetime *lft_soft; /* SADB_EXT_LIFETIME_SOFT */
! 680: struct sadb_address *src; /* SADB_EXT_ADDRESS_SRC */
! 681: struct sadb_address *dst; /* SADB_EXT_ADDRESS_DST */
! 682: struct sadb_address *proxy; /* SADB_EXT_ADDRESS_PROXY */
! 683: struct sadb_key *key_auth; /* SADB_EXT_KEY_AUTH */
! 684: struct sadb_key *key_encr; /* SADB_EXT_KEY_ENCRYPT */
! 685: struct sadb_ident *id_src; /* SADB_EXT_IDENTITY_SRC */
! 686: struct sadb_ident *id_dst; /* SADB_EXT_IDENTITY_DST */
! 687: struct sadb_sens *sensitivity; /* SADB_EXT_SENSITIVITY */
! 688: struct sadb_prop *proposal; /* SADB_EXT_PROPOSAL */
! 689: struct sadb_supported *supported_auth; /* SADB_EXT_SUPPORTED_AUTH */
! 690: struct sadb_supported *supported_encr; /* SADB_EXT_SUPPORTED_ENCRYPT */
! 691: struct sadb_spirange *spirange; /* SADB_EXT_SPIRANGE */
! 692: struct sadb_x_kmprivate *x_kmprivate; /* SADB_X_EXT_KMPRIVATE */
! 693: struct sadb_x_policy *x_policy; /* SADB_X_EXT_POLICY */
! 694: struct sadb_x_sa2 *x_sa2; /* SADB_X_EXT_SA2 */
! 695: #if defined(__linux__) || defined (__FreeBSD__)
! 696: struct sadb_x_nat_t_type *x_natt_type; /* SADB_X_EXT_NAT_T_TYPE */
! 697: struct sadb_x_nat_t_port *x_natt_sport; /* SADB_X_EXT_NAT_T_SPORT */
! 698: struct sadb_x_nat_t_port *x_natt_dport; /* SADB_X_EXT_NAT_T_DPORT */
! 699: #ifdef __linux__
! 700: struct sadb_address *x_natt_oa; /* SADB_X_EXT_NAT_T_OA */
! 701: struct sadb_x_sec_ctx *x_sec_ctx; /* SADB_X_EXT_SEC_CTX */
! 702: struct sadb_x_kmaddress *x_kmaddress; /* SADB_X_EXT_KMADDRESS */
! 703: #else
! 704: struct sadb_address *x_natt_oai; /* SADB_X_EXT_NAT_T_OAI */
! 705: struct sadb_address *x_natt_oar; /* SADB_X_EXT_NAT_T_OAR */
! 706: #ifdef SADB_X_EXT_NAT_T_FRAG
! 707: struct sadb_x_nat_t_frag *x_natt_frag; /* SADB_X_EXT_NAT_T_FRAG */
! 708: #ifdef SADB_X_EXT_SA_REPLAY
! 709: struct sadb_x_sa_replay *x_replay; /* SADB_X_EXT_SA_REPLAY */
! 710: struct sadb_address *x_new_addr_src; /* SADB_X_EXT_NEW_ADDRESS_SRC */
! 711: struct sadb_address *x_new_addr_dst; /* SADB_X_EXT_NEW_ADDRESS_DST */
! 712: #endif
! 713: #endif
! 714: #endif /* __linux__ */
! 715: #endif /* __linux__ || __FreeBSD__ */
! 716: } __attribute__((__packed__));
! 717: };
! 718: };
! 719:
! 720: ENUM(sadb_ext_type_names, SADB_EXT_RESERVED, SADB_EXT_MAX,
! 721: "SADB_EXT_RESERVED",
! 722: "SADB_EXT_SA",
! 723: "SADB_EXT_LIFETIME_CURRENT",
! 724: "SADB_EXT_LIFETIME_HARD",
! 725: "SADB_EXT_LIFETIME_SOFT",
! 726: "SADB_EXT_ADDRESS_SRC",
! 727: "SADB_EXT_ADDRESS_DST",
! 728: "SADB_EXT_ADDRESS_PROXY",
! 729: "SADB_EXT_KEY_AUTH",
! 730: "SADB_EXT_KEY_ENCRYPT",
! 731: "SADB_EXT_IDENTITY_SRC",
! 732: "SADB_EXT_IDENTITY_DST",
! 733: "SADB_EXT_SENSITIVITY",
! 734: "SADB_EXT_PROPOSAL",
! 735: "SADB_EXT_SUPPORTED_AUTH",
! 736: "SADB_EXT_SUPPORTED_ENCRYPT",
! 737: "SADB_EXT_SPIRANGE",
! 738: "SADB_X_EXT_KMPRIVATE",
! 739: "SADB_X_EXT_POLICY",
! 740: "SADB_X_EXT_SA2",
! 741: #ifdef __APPLE__
! 742: "SADB_EXT_SESSION_ID",
! 743: "SADB_EXT_SASTAT",
! 744: "SADB_X_EXT_IPSECIF",
! 745: "SADB_X_EXT_ADDR_RANGE_SRC_START",
! 746: "SADB_X_EXT_ADDR_RANGE_SRC_END",
! 747: "SADB_X_EXT_ADDR_RANGE_DST_START",
! 748: "SADB_X_EXT_ADDR_RANGE_DST_END",
! 749: "SADB_EXT_MIGRATE_ADDRESS_SRC",
! 750: "SADB_EXT_MIGRATE_ADDRESS_DST",
! 751: "SADB_X_EXT_MIGRATE_IPSECIF",
! 752: #else
! 753: "SADB_X_EXT_NAT_T_TYPE",
! 754: "SADB_X_EXT_NAT_T_SPORT",
! 755: "SADB_X_EXT_NAT_T_DPORT",
! 756: #ifdef __linux__
! 757: "SADB_X_EXT_NAT_T_OA",
! 758: "SADB_X_EXT_SEC_CTX",
! 759: "SADB_X_EXT_KMADDRESS",
! 760: #else
! 761: "SADB_X_EXT_NAT_T_OAI",
! 762: "SADB_X_EXT_NAT_T_OAR",
! 763: "SADB_X_EXT_NAT_T_FRAG",
! 764: "SADB_X_EXT_SA_REPLAY",
! 765: "SADB_X_EXT_NEW_ADDRESS_SRC",
! 766: "SADB_X_EXT_NEW_ADDRESS_DST",
! 767: #endif /* __linux__ */
! 768: #endif /* __APPLE__ */
! 769: );
! 770:
! 771: /**
! 772: * convert a protocol identifier to the PF_KEY sa type
! 773: */
! 774: static uint8_t proto2satype(uint8_t proto)
! 775: {
! 776: switch (proto)
! 777: {
! 778: case IPPROTO_ESP:
! 779: return SADB_SATYPE_ESP;
! 780: case IPPROTO_AH:
! 781: return SADB_SATYPE_AH;
! 782: case IPPROTO_COMP:
! 783: return SADB_X_SATYPE_IPCOMP;
! 784: default:
! 785: return proto;
! 786: }
! 787: }
! 788:
! 789: /**
! 790: * convert a PF_KEY sa type to a protocol identifier
! 791: */
! 792: static uint8_t satype2proto(uint8_t satype)
! 793: {
! 794: switch (satype)
! 795: {
! 796: case SADB_SATYPE_ESP:
! 797: return IPPROTO_ESP;
! 798: case SADB_SATYPE_AH:
! 799: return IPPROTO_AH;
! 800: case SADB_X_SATYPE_IPCOMP:
! 801: return IPPROTO_COMP;
! 802: default:
! 803: return satype;
! 804: }
! 805: }
! 806:
! 807: /**
! 808: * convert the general ipsec mode to the one defined in ipsec.h
! 809: */
! 810: static uint8_t mode2kernel(ipsec_mode_t mode)
! 811: {
! 812: switch (mode)
! 813: {
! 814: case MODE_TRANSPORT:
! 815: return IPSEC_MODE_TRANSPORT;
! 816: case MODE_TUNNEL:
! 817: return IPSEC_MODE_TUNNEL;
! 818: #ifdef HAVE_IPSEC_MODE_BEET
! 819: case MODE_BEET:
! 820: return IPSEC_MODE_BEET;
! 821: #endif
! 822: default:
! 823: return mode;
! 824: }
! 825: }
! 826:
! 827: /**
! 828: * convert the general policy direction to the one defined in ipsec.h
! 829: */
! 830: static uint8_t dir2kernel(policy_dir_t dir)
! 831: {
! 832: switch (dir)
! 833: {
! 834: case POLICY_IN:
! 835: return IPSEC_DIR_INBOUND;
! 836: case POLICY_OUT:
! 837: return IPSEC_DIR_OUTBOUND;
! 838: #ifdef HAVE_IPSEC_DIR_FWD
! 839: case POLICY_FWD:
! 840: return IPSEC_DIR_FWD;
! 841: #endif
! 842: default:
! 843: return IPSEC_DIR_INVALID;
! 844: }
! 845: }
! 846:
! 847: /**
! 848: * convert the policy type to the one defined in ipsec.h
! 849: */
! 850: static inline uint16_t type2kernel(policy_type_t type)
! 851: {
! 852: switch (type)
! 853: {
! 854: case POLICY_IPSEC:
! 855: return IPSEC_POLICY_IPSEC;
! 856: case POLICY_PASS:
! 857: return IPSEC_POLICY_NONE;
! 858: case POLICY_DROP:
! 859: return IPSEC_POLICY_DISCARD;
! 860: }
! 861: return type;
! 862: }
! 863:
! 864: #ifdef SADB_X_MIGRATE
! 865: /**
! 866: * convert the policy direction in ipsec.h to the general one.
! 867: */
! 868: static policy_dir_t kernel2dir(uint8_t dir)
! 869: {
! 870: switch (dir)
! 871: {
! 872: case IPSEC_DIR_INBOUND:
! 873: return POLICY_IN;
! 874: case IPSEC_DIR_OUTBOUND:
! 875: return POLICY_OUT;
! 876: #ifdef HAVE_IPSEC_DIR_FWD
! 877: case IPSEC_DIR_FWD:
! 878: return POLICY_FWD;
! 879: #endif
! 880: default:
! 881: return dir;
! 882: }
! 883: }
! 884: #endif /*SADB_X_MIGRATE*/
! 885:
! 886: typedef struct kernel_algorithm_t kernel_algorithm_t;
! 887:
! 888: /**
! 889: * Mapping of IKEv2 algorithms to PF_KEY algorithms
! 890: */
! 891: struct kernel_algorithm_t {
! 892: /**
! 893: * Identifier specified in IKEv2
! 894: */
! 895: int ikev2;
! 896:
! 897: /**
! 898: * Identifier as defined in pfkeyv2.h
! 899: */
! 900: int kernel;
! 901: };
! 902:
! 903: #define END_OF_LIST -1
! 904:
! 905: /**
! 906: * Algorithms for encryption
! 907: */
! 908: static kernel_algorithm_t encryption_algs[] = {
! 909: /* {ENCR_DES_IV64, 0 }, */
! 910: {ENCR_DES, SADB_EALG_DESCBC },
! 911: {ENCR_3DES, SADB_EALG_3DESCBC },
! 912: /* {ENCR_RC5, 0 }, */
! 913: /* {ENCR_IDEA, 0 }, */
! 914: {ENCR_CAST, SADB_X_EALG_CASTCBC },
! 915: {ENCR_BLOWFISH, SADB_X_EALG_BLOWFISHCBC },
! 916: /* {ENCR_3IDEA, 0 }, */
! 917: /* {ENCR_DES_IV32, 0 }, */
! 918: {ENCR_NULL, SADB_EALG_NULL },
! 919: {ENCR_AES_CBC, SADB_X_EALG_AESCBC },
! 920: #ifdef SADB_X_EALG_AESCTR
! 921: {ENCR_AES_CTR, SADB_X_EALG_AESCTR },
! 922: #endif
! 923: /* {ENCR_AES_CCM_ICV8, SADB_X_EALG_AES_CCM_ICV8 }, */
! 924: /* {ENCR_AES_CCM_ICV12, SADB_X_EALG_AES_CCM_ICV12 }, */
! 925: /* {ENCR_AES_CCM_ICV16, SADB_X_EALG_AES_CCM_ICV16 }, */
! 926: #ifdef SADB_X_EALG_AES_GCM_ICV8 /* assume the others are defined too */
! 927: {ENCR_AES_GCM_ICV8, SADB_X_EALG_AES_GCM_ICV8 },
! 928: {ENCR_AES_GCM_ICV12, SADB_X_EALG_AES_GCM_ICV12 },
! 929: {ENCR_AES_GCM_ICV16, SADB_X_EALG_AES_GCM_ICV16 },
! 930: #elif defined(SADB_X_EALG_AES_GCM) /* macOS */
! 931: {ENCR_AES_GCM_ICV16, SADB_X_EALG_AES_GCM },
! 932: #endif
! 933: #ifdef SADB_X_EALG_CAMELLIACBC
! 934: {ENCR_CAMELLIA_CBC, SADB_X_EALG_CAMELLIACBC },
! 935: #endif
! 936: #ifdef SADB_X_EALG_CHACHA20POLY1305
! 937: {ENCR_CHACHA20_POLY1305, SADB_X_EALG_CHACHA20POLY1305},
! 938: #endif
! 939: {END_OF_LIST, 0 },
! 940: };
! 941:
! 942: /**
! 943: * Algorithms for integrity protection
! 944: */
! 945: static kernel_algorithm_t integrity_algs[] = {
! 946: {AUTH_HMAC_MD5_96, SADB_AALG_MD5HMAC },
! 947: {AUTH_HMAC_SHA1_96, SADB_AALG_SHA1HMAC },
! 948: {AUTH_HMAC_SHA2_256_128, SADB_X_AALG_SHA2_256HMAC },
! 949: {AUTH_HMAC_SHA2_384_192, SADB_X_AALG_SHA2_384HMAC },
! 950: {AUTH_HMAC_SHA2_512_256, SADB_X_AALG_SHA2_512HMAC },
! 951: /* {AUTH_DES_MAC, 0, }, */
! 952: /* {AUTH_KPDK_MD5, 0, }, */
! 953: #ifdef SADB_X_AALG_AES_XCBC_MAC
! 954: {AUTH_AES_XCBC_96, SADB_X_AALG_AES_XCBC_MAC, },
! 955: #endif
! 956: {END_OF_LIST, 0, },
! 957: };
! 958:
! 959: /**
! 960: * Algorithms for IPComp, unused yet
! 961: */
! 962: static kernel_algorithm_t compression_algs[] = {
! 963: /* {IPCOMP_OUI, 0 }, */
! 964: {IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE },
! 965: #ifdef SADB_X_CALG_LZS
! 966: {IPCOMP_LZS, SADB_X_CALG_LZS },
! 967: #endif
! 968: #ifdef SADB_X_CALG_LZJH
! 969: {IPCOMP_LZJH, SADB_X_CALG_LZJH },
! 970: #endif
! 971: {END_OF_LIST, 0 },
! 972: };
! 973:
! 974: /**
! 975: * Look up a kernel algorithm ID and its key size
! 976: */
! 977: static int lookup_algorithm(transform_type_t type, int ikev2)
! 978: {
! 979: kernel_algorithm_t *list;
! 980: uint16_t alg = 0;
! 981:
! 982: switch (type)
! 983: {
! 984: case ENCRYPTION_ALGORITHM:
! 985: list = encryption_algs;
! 986: break;
! 987: case INTEGRITY_ALGORITHM:
! 988: list = integrity_algs;
! 989: break;
! 990: case COMPRESSION_ALGORITHM:
! 991: list = compression_algs;
! 992: break;
! 993: default:
! 994: return 0;
! 995: }
! 996: while (list->ikev2 != END_OF_LIST)
! 997: {
! 998: if (ikev2 == list->ikev2)
! 999: {
! 1000: return list->kernel;
! 1001: }
! 1002: list++;
! 1003: }
! 1004: charon->kernel->lookup_algorithm(charon->kernel, ikev2, type, &alg, NULL);
! 1005: return alg;
! 1006: }
! 1007:
! 1008: /**
! 1009: * Helper to set a port in a sockaddr_t, the port has to be in host order
! 1010: */
! 1011: static void set_port(sockaddr_t *addr, uint16_t port)
! 1012: {
! 1013: switch (addr->sa_family)
! 1014: {
! 1015: case AF_INET:
! 1016: {
! 1017: struct sockaddr_in *sin = (struct sockaddr_in*)addr;
! 1018: sin->sin_port = htons(port);
! 1019: break;
! 1020: }
! 1021: case AF_INET6:
! 1022: {
! 1023: struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
! 1024: sin6->sin6_port = htons(port);
! 1025: break;
! 1026: }
! 1027: }
! 1028: }
! 1029:
! 1030: /**
! 1031: * Copy a host_t as sockaddr_t to the given memory location.
! 1032: * @return the number of bytes copied
! 1033: */
! 1034: static size_t hostcpy(void *dest, host_t *host, bool include_port)
! 1035: {
! 1036: sockaddr_t *addr = host->get_sockaddr(host), *dest_addr = dest;
! 1037: socklen_t *len = host->get_sockaddr_len(host);
! 1038:
! 1039: memcpy(dest, addr, *len);
! 1040: #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
! 1041: dest_addr->sa_len = *len;
! 1042: #endif
! 1043: if (!include_port)
! 1044: {
! 1045: set_port(dest_addr, 0);
! 1046: }
! 1047: return *len;
! 1048: }
! 1049:
! 1050: /**
! 1051: * add a host to the given sadb_msg
! 1052: */
! 1053: static void add_addr_ext(struct sadb_msg *msg, host_t *host, uint16_t type,
! 1054: uint8_t proto, uint8_t prefixlen, bool include_port)
! 1055: {
! 1056: struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg);
! 1057: size_t len;
! 1058:
! 1059: addr->sadb_address_exttype = type;
! 1060: addr->sadb_address_proto = proto;
! 1061: addr->sadb_address_prefixlen = prefixlen;
! 1062: len = hostcpy(addr + 1, host, include_port);
! 1063: addr->sadb_address_len = PFKEY_LEN(sizeof(*addr) + len);
! 1064: PFKEY_EXT_ADD(msg, addr);
! 1065: }
! 1066:
! 1067: #ifdef HAVE_NATT
! 1068: /**
! 1069: * add udp encap extensions to a sadb_msg
! 1070: */
! 1071: static void add_encap_ext(struct sadb_msg *msg, host_t *src, host_t *dst)
! 1072: {
! 1073: struct sadb_x_nat_t_type* nat_type;
! 1074: struct sadb_x_nat_t_port* nat_port;
! 1075:
! 1076: nat_type = (struct sadb_x_nat_t_type*)PFKEY_EXT_ADD_NEXT(msg);
! 1077: nat_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
! 1078: nat_type->sadb_x_nat_t_type_len = PFKEY_LEN(sizeof(*nat_type));
! 1079: nat_type->sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP;
! 1080: PFKEY_EXT_ADD(msg, nat_type);
! 1081:
! 1082: nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg);
! 1083: nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
! 1084: nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(*nat_port));
! 1085: nat_port->sadb_x_nat_t_port_port = htons(src->get_port(src));
! 1086: PFKEY_EXT_ADD(msg, nat_port);
! 1087:
! 1088: nat_port = (struct sadb_x_nat_t_port*)PFKEY_EXT_ADD_NEXT(msg);
! 1089: nat_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
! 1090: nat_port->sadb_x_nat_t_port_len = PFKEY_LEN(sizeof(*nat_port));
! 1091: nat_port->sadb_x_nat_t_port_port = htons(dst->get_port(dst));
! 1092: PFKEY_EXT_ADD(msg, nat_port);
! 1093: }
! 1094: #endif /*HAVE_NATT*/
! 1095:
! 1096: /**
! 1097: * Convert a sadb_address to a traffic_selector
! 1098: */
! 1099: static traffic_selector_t* sadb_address2ts(struct sadb_address *address)
! 1100: {
! 1101: traffic_selector_t *ts;
! 1102: host_t *host;
! 1103: uint8_t proto;
! 1104:
! 1105: proto = address->sadb_address_proto;
! 1106: proto = proto == IPSEC_PROTO_ANY ? 0 : proto;
! 1107:
! 1108: /* The Linux 2.6 kernel does not set the protocol and port information
! 1109: * in the src and dst sadb_address extensions of the SADB_ACQUIRE message.
! 1110: */
! 1111: host = host_create_from_sockaddr((sockaddr_t*)&address[1]);
! 1112: ts = traffic_selector_create_from_subnet(host,
! 1113: address->sadb_address_prefixlen,
! 1114: proto, host->get_port(host),
! 1115: host->get_port(host) ?: 65535);
! 1116: return ts;
! 1117: }
! 1118:
! 1119: /**
! 1120: * Parses a pfkey message received from the kernel
! 1121: */
! 1122: static status_t parse_pfkey_message(struct sadb_msg *msg, pfkey_msg_t *out)
! 1123: {
! 1124: struct sadb_ext* ext;
! 1125: size_t len;
! 1126:
! 1127: memset(out, 0, sizeof(pfkey_msg_t));
! 1128: out->msg = msg;
! 1129:
! 1130: len = msg->sadb_msg_len;
! 1131: len -= PFKEY_LEN(sizeof(struct sadb_msg));
! 1132:
! 1133: ext = (struct sadb_ext*)(((char*)msg) + sizeof(struct sadb_msg));
! 1134:
! 1135: while (len >= PFKEY_LEN(sizeof(struct sadb_ext)))
! 1136: {
! 1137: DBG3(DBG_KNL, " %N", sadb_ext_type_names, ext->sadb_ext_type);
! 1138: if (ext->sadb_ext_len < PFKEY_LEN(sizeof(struct sadb_ext)) ||
! 1139: ext->sadb_ext_len > len)
! 1140: {
! 1141: DBG1(DBG_KNL, "length of %N extension is invalid",
! 1142: sadb_ext_type_names, ext->sadb_ext_type);
! 1143: break;
! 1144: }
! 1145:
! 1146: if ((ext->sadb_ext_type > SADB_EXT_MAX) || (!ext->sadb_ext_type))
! 1147: {
! 1148: DBG1(DBG_KNL, "type of PF_KEY extension (%d) is invalid",
! 1149: ext->sadb_ext_type);
! 1150: break;
! 1151: }
! 1152:
! 1153: if (out->ext[ext->sadb_ext_type])
! 1154: {
! 1155: DBG1(DBG_KNL, "duplicate %N extension",
! 1156: sadb_ext_type_names, ext->sadb_ext_type);
! 1157: break;
! 1158: }
! 1159:
! 1160: out->ext[ext->sadb_ext_type] = ext;
! 1161: ext = PFKEY_EXT_NEXT_LEN(ext, len);
! 1162: }
! 1163:
! 1164: if (len)
! 1165: {
! 1166: DBG1(DBG_KNL, "PF_KEY message length is invalid");
! 1167: return FAILED;
! 1168: }
! 1169:
! 1170: return SUCCESS;
! 1171: }
! 1172:
! 1173: /**
! 1174: * Send a message to a specific PF_KEY socket and handle the response.
! 1175: */
! 1176: static status_t pfkey_send_socket(private_kernel_pfkey_ipsec_t *this, int socket,
! 1177: struct sadb_msg *in, struct sadb_msg **out, size_t *out_len)
! 1178: {
! 1179: unsigned char buf[PFKEY_BUFFER_SIZE];
! 1180: struct sadb_msg *msg;
! 1181: int in_len, len;
! 1182:
! 1183: this->mutex_pfkey->lock(this->mutex_pfkey);
! 1184:
! 1185: /* the kernel may broadcast messages not related to our requests (e.g. when
! 1186: * managing SAs and policies via an external tool), so let's clear the
! 1187: * receive buffer so there is room for our request and its reply. */
! 1188: while (TRUE)
! 1189: {
! 1190: len = recv(socket, buf, sizeof(buf), MSG_DONTWAIT);
! 1191:
! 1192: if (len < 0)
! 1193: {
! 1194: if (errno == EINTR)
! 1195: { /* interrupted, try again */
! 1196: continue;
! 1197: }
! 1198: break;
! 1199: }
! 1200: }
! 1201:
! 1202: /* FIXME: our usage of sequence numbers is probably wrong. check RFC 2367,
! 1203: * in particular the behavior in response to an SADB_ACQUIRE. */
! 1204: in->sadb_msg_seq = ++this->seq;
! 1205: in->sadb_msg_pid = getpid();
! 1206:
! 1207: in_len = PFKEY_USER_LEN(in->sadb_msg_len);
! 1208:
! 1209: while (TRUE)
! 1210: {
! 1211: len = send(socket, in, in_len, 0);
! 1212:
! 1213: if (len != in_len)
! 1214: {
! 1215: if (errno == EINTR)
! 1216: {
! 1217: /* interrupted, try again */
! 1218: continue;
! 1219: }
! 1220: this->mutex_pfkey->unlock(this->mutex_pfkey);
! 1221: DBG1(DBG_KNL, "error sending to PF_KEY socket: %s",
! 1222: strerror(errno));
! 1223: return FAILED;
! 1224: }
! 1225: break;
! 1226: }
! 1227:
! 1228: while (TRUE)
! 1229: {
! 1230: msg = (struct sadb_msg*)buf;
! 1231:
! 1232: len = recv(socket, buf, sizeof(buf), 0);
! 1233:
! 1234: if (len < 0)
! 1235: {
! 1236: if (errno == EINTR)
! 1237: {
! 1238: DBG1(DBG_KNL, "got interrupted");
! 1239: /* interrupted, try again */
! 1240: continue;
! 1241: }
! 1242: DBG1(DBG_KNL, "error reading from PF_KEY socket: %s",
! 1243: strerror(errno));
! 1244: this->mutex_pfkey->unlock(this->mutex_pfkey);
! 1245: return FAILED;
! 1246: }
! 1247: if (len < sizeof(struct sadb_msg) ||
! 1248: msg->sadb_msg_len < PFKEY_LEN(sizeof(struct sadb_msg)))
! 1249: {
! 1250: DBG1(DBG_KNL, "received corrupted PF_KEY message");
! 1251: this->mutex_pfkey->unlock(this->mutex_pfkey);
! 1252: return FAILED;
! 1253: }
! 1254: if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT)
! 1255: {
! 1256: DBG1(DBG_KNL, "buffer was too small to receive the complete PF_KEY "
! 1257: "message");
! 1258: this->mutex_pfkey->unlock(this->mutex_pfkey);
! 1259: return FAILED;
! 1260: }
! 1261: if (msg->sadb_msg_pid != in->sadb_msg_pid)
! 1262: {
! 1263: DBG2(DBG_KNL, "received PF_KEY message is not intended for us");
! 1264: continue;
! 1265: }
! 1266: if (msg->sadb_msg_seq != this->seq)
! 1267: {
! 1268: DBG2(DBG_KNL, "received PF_KEY message with unexpected sequence "
! 1269: "number, was %d expected %d", msg->sadb_msg_seq,
! 1270: this->seq);
! 1271: if (msg->sadb_msg_seq == 0)
! 1272: {
! 1273: /* FreeBSD and Mac OS X do this for the response to
! 1274: * SADB_X_SPDGET (but not for the response to SADB_GET).
! 1275: * FreeBSD: 'key_spdget' in /usr/src/sys/netipsec/key.c. */
! 1276: }
! 1277: else if (msg->sadb_msg_seq < this->seq)
! 1278: {
! 1279: continue;
! 1280: }
! 1281: else
! 1282: {
! 1283: this->mutex_pfkey->unlock(this->mutex_pfkey);
! 1284: return FAILED;
! 1285: }
! 1286: }
! 1287: if (msg->sadb_msg_type != in->sadb_msg_type)
! 1288: {
! 1289: DBG2(DBG_KNL, "received PF_KEY message of wrong type, "
! 1290: "was %d expected %d, ignoring", msg->sadb_msg_type,
! 1291: in->sadb_msg_type);
! 1292: }
! 1293: break;
! 1294: }
! 1295:
! 1296: *out_len = len;
! 1297: *out = (struct sadb_msg*)malloc(len);
! 1298: memcpy(*out, buf, len);
! 1299:
! 1300: this->mutex_pfkey->unlock(this->mutex_pfkey);
! 1301: return SUCCESS;
! 1302: }
! 1303:
! 1304: /**
! 1305: * Send a message to the default PF_KEY socket and handle the response.
! 1306: */
! 1307: static status_t pfkey_send(private_kernel_pfkey_ipsec_t *this,
! 1308: struct sadb_msg *in, struct sadb_msg **out,
! 1309: size_t *out_len)
! 1310: {
! 1311: return pfkey_send_socket(this, this->socket, in, out, out_len);
! 1312: }
! 1313:
! 1314: /**
! 1315: * Process a SADB_ACQUIRE message from the kernel
! 1316: */
! 1317: static void process_acquire(private_kernel_pfkey_ipsec_t *this,
! 1318: struct sadb_msg* msg)
! 1319: {
! 1320: pfkey_msg_t response;
! 1321: uint32_t index, reqid = 0;
! 1322: traffic_selector_t *src_ts, *dst_ts;
! 1323: policy_entry_t *policy;
! 1324: policy_sa_t *sa;
! 1325:
! 1326: switch (msg->sadb_msg_satype)
! 1327: {
! 1328: case SADB_SATYPE_UNSPEC:
! 1329: case SADB_SATYPE_ESP:
! 1330: case SADB_SATYPE_AH:
! 1331: break;
! 1332: default:
! 1333: /* acquire for AH/ESP only */
! 1334: return;
! 1335: }
! 1336: DBG2(DBG_KNL, "received an SADB_ACQUIRE");
! 1337:
! 1338: if (parse_pfkey_message(msg, &response) != SUCCESS)
! 1339: {
! 1340: DBG1(DBG_KNL, "parsing SADB_ACQUIRE from kernel failed");
! 1341: return;
! 1342: }
! 1343:
! 1344: if (response.x_sa2)
! 1345: {
! 1346: reqid = response.x_sa2->sadb_x_sa2_reqid;
! 1347: }
! 1348: else
! 1349: {
! 1350: index = response.x_policy->sadb_x_policy_id;
! 1351: this->mutex->lock(this->mutex);
! 1352: if (this->policies->find_first(this->policies, policy_entry_match_byindex,
! 1353: (void**)&policy, index) &&
! 1354: policy->used_by->get_first(policy->used_by, (void**)&sa) == SUCCESS)
! 1355: {
! 1356: reqid = sa->sa->cfg.reqid;
! 1357: }
! 1358: else
! 1359: {
! 1360: DBG1(DBG_KNL, "received an SADB_ACQUIRE with policy id %d but no "
! 1361: "matching policy found", index);
! 1362: }
! 1363: this->mutex->unlock(this->mutex);
! 1364: }
! 1365:
! 1366: src_ts = sadb_address2ts(response.src);
! 1367: dst_ts = sadb_address2ts(response.dst);
! 1368:
! 1369: charon->kernel->acquire(charon->kernel, reqid, src_ts, dst_ts);
! 1370: }
! 1371:
! 1372: /**
! 1373: * Process a SADB_EXPIRE message from the kernel
! 1374: */
! 1375: static void process_expire(private_kernel_pfkey_ipsec_t *this,
! 1376: struct sadb_msg* msg)
! 1377: {
! 1378: pfkey_msg_t response;
! 1379: uint8_t protocol;
! 1380: uint32_t spi;
! 1381: host_t *dst;
! 1382: bool hard;
! 1383:
! 1384: DBG2(DBG_KNL, "received an SADB_EXPIRE");
! 1385:
! 1386: if (parse_pfkey_message(msg, &response) != SUCCESS)
! 1387: {
! 1388: DBG1(DBG_KNL, "parsing SADB_EXPIRE from kernel failed");
! 1389: return;
! 1390: }
! 1391:
! 1392: protocol = satype2proto(msg->sadb_msg_satype);
! 1393: spi = response.sa->sadb_sa_spi;
! 1394: hard = response.lft_hard != NULL;
! 1395:
! 1396: if (protocol == IPPROTO_ESP || protocol == IPPROTO_AH)
! 1397: {
! 1398: dst = host_create_from_sockaddr((sockaddr_t*)(response.dst + 1));
! 1399: if (dst)
! 1400: {
! 1401: charon->kernel->expire(charon->kernel, protocol, spi, dst, hard);
! 1402: dst->destroy(dst);
! 1403: }
! 1404: }
! 1405: }
! 1406:
! 1407: #ifdef SADB_X_MIGRATE
! 1408: /**
! 1409: * Process a SADB_X_MIGRATE message from the kernel
! 1410: */
! 1411: static void process_migrate(private_kernel_pfkey_ipsec_t *this,
! 1412: struct sadb_msg* msg)
! 1413: {
! 1414: pfkey_msg_t response;
! 1415: traffic_selector_t *src_ts, *dst_ts;
! 1416: policy_dir_t dir;
! 1417: uint32_t reqid = 0;
! 1418: host_t *local = NULL, *remote = NULL;
! 1419:
! 1420: DBG2(DBG_KNL, "received an SADB_X_MIGRATE");
! 1421:
! 1422: if (parse_pfkey_message(msg, &response) != SUCCESS)
! 1423: {
! 1424: DBG1(DBG_KNL, "parsing SADB_X_MIGRATE from kernel failed");
! 1425: return;
! 1426: }
! 1427: src_ts = sadb_address2ts(response.src);
! 1428: dst_ts = sadb_address2ts(response.dst);
! 1429: dir = kernel2dir(response.x_policy->sadb_x_policy_dir);
! 1430: DBG2(DBG_KNL, " policy %R === %R %N, id %u", src_ts, dst_ts,
! 1431: policy_dir_names, dir);
! 1432:
! 1433: /* SADB_X_EXT_KMADDRESS is not present in unpatched kernels < 2.6.28 */
! 1434: if (response.x_kmaddress)
! 1435: {
! 1436: sockaddr_t *local_addr, *remote_addr;
! 1437: uint32_t local_len;
! 1438:
! 1439: local_addr = (sockaddr_t*)&response.x_kmaddress[1];
! 1440: local = host_create_from_sockaddr(local_addr);
! 1441: local_len = (local_addr->sa_family == AF_INET6)?
! 1442: sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
! 1443: remote_addr = (sockaddr_t*)((uint8_t*)local_addr + local_len);
! 1444: remote = host_create_from_sockaddr(remote_addr);
! 1445: DBG2(DBG_KNL, " kmaddress: %H...%H", local, remote);
! 1446: }
! 1447:
! 1448: if (src_ts && dst_ts && local && remote)
! 1449: {
! 1450: charon->kernel->migrate(charon->kernel, reqid, src_ts, dst_ts, dir,
! 1451: local, remote);
! 1452: }
! 1453: else
! 1454: {
! 1455: DESTROY_IF(src_ts);
! 1456: DESTROY_IF(dst_ts);
! 1457: DESTROY_IF(local);
! 1458: DESTROY_IF(remote);
! 1459: }
! 1460: }
! 1461: #endif /*SADB_X_MIGRATE*/
! 1462:
! 1463: #ifdef SADB_X_NAT_T_NEW_MAPPING
! 1464: /**
! 1465: * Process a SADB_X_NAT_T_NEW_MAPPING message from the kernel
! 1466: */
! 1467: static void process_mapping(private_kernel_pfkey_ipsec_t *this,
! 1468: struct sadb_msg* msg)
! 1469: {
! 1470: pfkey_msg_t response;
! 1471: uint32_t spi;
! 1472: sockaddr_t *sa;
! 1473: host_t *dst, *new;
! 1474:
! 1475: DBG2(DBG_KNL, "received an SADB_X_NAT_T_NEW_MAPPING");
! 1476:
! 1477: if (parse_pfkey_message(msg, &response) != SUCCESS)
! 1478: {
! 1479: DBG1(DBG_KNL, "parsing SADB_X_NAT_T_NEW_MAPPING from kernel failed");
! 1480: return;
! 1481: }
! 1482:
! 1483: if (!response.x_sa2)
! 1484: {
! 1485: DBG1(DBG_KNL, "received SADB_X_NAT_T_NEW_MAPPING is missing required "
! 1486: "information");
! 1487: return;
! 1488: }
! 1489:
! 1490: spi = response.sa->sadb_sa_spi;
! 1491:
! 1492: if (satype2proto(msg->sadb_msg_satype) != IPPROTO_ESP)
! 1493: {
! 1494: return;
! 1495: }
! 1496:
! 1497: sa = (sockaddr_t*)(response.dst + 1);
! 1498: dst = host_create_from_sockaddr(sa);
! 1499: switch (sa->sa_family)
! 1500: {
! 1501: case AF_INET:
! 1502: {
! 1503: struct sockaddr_in *sin = (struct sockaddr_in*)sa;
! 1504: sin->sin_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
! 1505: break;
! 1506: }
! 1507: case AF_INET6:
! 1508: {
! 1509: struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
! 1510: sin6->sin6_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port);
! 1511: break;
! 1512: }
! 1513: default:
! 1514: break;
! 1515: }
! 1516: if (dst)
! 1517: {
! 1518: new = host_create_from_sockaddr(sa);
! 1519: if (new)
! 1520: {
! 1521: charon->kernel->mapping(charon->kernel, IPPROTO_ESP, spi, dst, new);
! 1522: new->destroy(new);
! 1523: }
! 1524: dst->destroy(dst);
! 1525: }
! 1526: }
! 1527: #endif /*SADB_X_NAT_T_NEW_MAPPING*/
! 1528:
! 1529: /**
! 1530: * Receives events from kernel
! 1531: */
! 1532: static bool receive_events(private_kernel_pfkey_ipsec_t *this, int fd,
! 1533: watcher_event_t event)
! 1534: {
! 1535: unsigned char buf[PFKEY_BUFFER_SIZE];
! 1536: struct sadb_msg *msg = (struct sadb_msg*)buf;
! 1537: int len;
! 1538:
! 1539: len = recvfrom(this->socket_events, buf, sizeof(buf), MSG_DONTWAIT, NULL, 0);
! 1540: if (len < 0)
! 1541: {
! 1542: switch (errno)
! 1543: {
! 1544: case EINTR:
! 1545: /* interrupted, try again */
! 1546: return TRUE;
! 1547: case EAGAIN:
! 1548: /* no data ready, select again */
! 1549: return TRUE;
! 1550: default:
! 1551: DBG1(DBG_KNL, "unable to receive from PF_KEY event socket");
! 1552: sleep(1);
! 1553: return TRUE;
! 1554: }
! 1555: }
! 1556:
! 1557: if (len < sizeof(struct sadb_msg) ||
! 1558: msg->sadb_msg_len < PFKEY_LEN(sizeof(struct sadb_msg)))
! 1559: {
! 1560: DBG2(DBG_KNL, "received corrupted PF_KEY message");
! 1561: return TRUE;
! 1562: }
! 1563: if (msg->sadb_msg_pid != 0)
! 1564: { /* not from kernel. not interested, try another one */
! 1565: return TRUE;
! 1566: }
! 1567: if (msg->sadb_msg_len > len / PFKEY_ALIGNMENT)
! 1568: {
! 1569: DBG1(DBG_KNL, "buffer was too small to receive the complete "
! 1570: "PF_KEY message");
! 1571: return TRUE;
! 1572: }
! 1573:
! 1574: switch (msg->sadb_msg_type)
! 1575: {
! 1576: case SADB_ACQUIRE:
! 1577: process_acquire(this, msg);
! 1578: break;
! 1579: case SADB_EXPIRE:
! 1580: process_expire(this, msg);
! 1581: break;
! 1582: #ifdef SADB_X_MIGRATE
! 1583: case SADB_X_MIGRATE:
! 1584: process_migrate(this, msg);
! 1585: break;
! 1586: #endif /*SADB_X_MIGRATE*/
! 1587: #ifdef SADB_X_NAT_T_NEW_MAPPING
! 1588: case SADB_X_NAT_T_NEW_MAPPING:
! 1589: process_mapping(this, msg);
! 1590: break;
! 1591: #endif /*SADB_X_NAT_T_NEW_MAPPING*/
! 1592: default:
! 1593: break;
! 1594: }
! 1595:
! 1596: return TRUE;
! 1597: }
! 1598:
! 1599: /**
! 1600: * Get an SPI for a specific protocol from the kernel.
! 1601: */
! 1602:
! 1603: static status_t get_spi_internal(private_kernel_pfkey_ipsec_t *this,
! 1604: host_t *src, host_t *dst, uint8_t proto, uint32_t min, uint32_t max,
! 1605: uint32_t *spi)
! 1606: {
! 1607: unsigned char request[PFKEY_BUFFER_SIZE];
! 1608: struct sadb_msg *msg, *out;
! 1609: struct sadb_spirange *range;
! 1610: pfkey_msg_t response;
! 1611: uint32_t received_spi = 0;
! 1612: size_t len;
! 1613:
! 1614: memset(&request, 0, sizeof(request));
! 1615:
! 1616: msg = (struct sadb_msg*)request;
! 1617: msg->sadb_msg_version = PF_KEY_V2;
! 1618: msg->sadb_msg_type = SADB_GETSPI;
! 1619: msg->sadb_msg_satype = proto2satype(proto);
! 1620: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 1621:
! 1622: add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE);
! 1623: add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
! 1624:
! 1625: range = (struct sadb_spirange*)PFKEY_EXT_ADD_NEXT(msg);
! 1626: range->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
! 1627: range->sadb_spirange_len = PFKEY_LEN(sizeof(struct sadb_spirange));
! 1628: range->sadb_spirange_min = min;
! 1629: range->sadb_spirange_max = max;
! 1630: PFKEY_EXT_ADD(msg, range);
! 1631:
! 1632: if (pfkey_send(this, msg, &out, &len) == SUCCESS)
! 1633: {
! 1634: if (out->sadb_msg_errno)
! 1635: {
! 1636: DBG1(DBG_KNL, "allocating SPI failed: %s (%d)",
! 1637: strerror(out->sadb_msg_errno), out->sadb_msg_errno);
! 1638: }
! 1639: else if (parse_pfkey_message(out, &response) == SUCCESS)
! 1640: {
! 1641: received_spi = response.sa->sadb_sa_spi;
! 1642: }
! 1643: free(out);
! 1644: }
! 1645:
! 1646: if (received_spi == 0)
! 1647: {
! 1648: return FAILED;
! 1649: }
! 1650:
! 1651: *spi = received_spi;
! 1652: return SUCCESS;
! 1653: }
! 1654:
! 1655: METHOD(kernel_ipsec_t, get_spi, status_t,
! 1656: private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
! 1657: uint8_t protocol, uint32_t *spi)
! 1658: {
! 1659: uint32_t spi_min, spi_max;
! 1660:
! 1661: spi_min = lib->settings->get_int(lib->settings, "%s.spi_min",
! 1662: KERNEL_SPI_MIN, lib->ns);
! 1663: spi_max = lib->settings->get_int(lib->settings, "%s.spi_max",
! 1664: KERNEL_SPI_MAX, lib->ns);
! 1665:
! 1666: if (get_spi_internal(this, src, dst, protocol, min(spi_min, spi_max),
! 1667: max(spi_min, spi_max), spi) != SUCCESS)
! 1668: {
! 1669: DBG1(DBG_KNL, "unable to get SPI");
! 1670: return FAILED;
! 1671: }
! 1672:
! 1673: DBG2(DBG_KNL, "got SPI %.8x", ntohl(*spi));
! 1674: return SUCCESS;
! 1675: }
! 1676:
! 1677: METHOD(kernel_ipsec_t, get_cpi, status_t,
! 1678: private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
! 1679: uint16_t *cpi)
! 1680: {
! 1681: uint32_t received_spi = 0;
! 1682:
! 1683: DBG2(DBG_KNL, "getting CPI");
! 1684:
! 1685: if (get_spi_internal(this, src, dst, IPPROTO_COMP,
! 1686: 0x100, 0xEFFF, &received_spi) != SUCCESS)
! 1687: {
! 1688: DBG1(DBG_KNL, "unable to get CPI");
! 1689: return FAILED;
! 1690: }
! 1691:
! 1692: *cpi = htons((uint16_t)ntohl(received_spi));
! 1693:
! 1694: DBG2(DBG_KNL, "got CPI %.4x", ntohs(*cpi));
! 1695: return SUCCESS;
! 1696: }
! 1697:
! 1698: METHOD(kernel_ipsec_t, add_sa, status_t,
! 1699: private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
! 1700: kernel_ipsec_add_sa_t *data)
! 1701: {
! 1702: unsigned char request[PFKEY_BUFFER_SIZE];
! 1703: struct sadb_msg *msg, *out;
! 1704: struct sadb_sa *sa;
! 1705: struct sadb_x_sa2 *sa2;
! 1706: struct sadb_lifetime *lft;
! 1707: struct sadb_key *key;
! 1708: size_t len;
! 1709: uint16_t ipcomp = data->ipcomp;
! 1710: ipsec_mode_t mode = data->mode;
! 1711:
! 1712: /* if IPComp is used, we install an additional IPComp SA. if the cpi is 0
! 1713: * we are in the recursive call below */
! 1714: if (ipcomp != IPCOMP_NONE && data->cpi != 0)
! 1715: {
! 1716: lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
! 1717: kernel_ipsec_sa_id_t ipcomp_id = {
! 1718: .src = id->src,
! 1719: .dst = id->dst,
! 1720: .spi = htonl(ntohs(data->cpi)),
! 1721: .proto = IPPROTO_COMP,
! 1722: .mark = id->mark,
! 1723: };
! 1724: kernel_ipsec_add_sa_t ipcomp_sa = {
! 1725: .reqid = data->reqid,
! 1726: .mode = data->mode,
! 1727: .src_ts = data->src_ts,
! 1728: .dst_ts = data->dst_ts,
! 1729: .lifetime = &lft,
! 1730: .enc_alg = ENCR_UNDEFINED,
! 1731: .int_alg = AUTH_UNDEFINED,
! 1732: .tfc = data->tfc,
! 1733: .ipcomp = data->ipcomp,
! 1734: .initiator = data->initiator,
! 1735: .inbound = data->inbound,
! 1736: .update = data->update,
! 1737: };
! 1738: add_sa(this, &ipcomp_id, &ipcomp_sa);
! 1739: ipcomp = IPCOMP_NONE;
! 1740: /* use transport mode ESP SA, IPComp uses tunnel mode */
! 1741: mode = MODE_TRANSPORT;
! 1742: }
! 1743:
! 1744: if (data->update)
! 1745: {
! 1746: /* As we didn't know the reqid during SPI allocation, we used reqid
! 1747: * zero. Unfortunately we can't SADB_UPDATE to the new reqid, hence we
! 1748: * have to delete the SPI allocation state manually. The reqid
! 1749: * selector does not count for that, therefore we have to delete
! 1750: * that state before installing the new SA to avoid deleting the
! 1751: * the new state after installing it. */
! 1752: kernel_ipsec_sa_id_t del_id = {
! 1753: .src = id->src,
! 1754: .dst = id->dst,
! 1755: .spi = id->spi,
! 1756: .proto = id->proto,
! 1757: };
! 1758: kernel_ipsec_del_sa_t del = { 0 };
! 1759:
! 1760: if (this->public.interface.del_sa(&this->public.interface, &del_id,
! 1761: &del) != SUCCESS)
! 1762: {
! 1763: DBG1(DBG_KNL, "deleting SPI allocation SA failed");
! 1764: }
! 1765: }
! 1766:
! 1767: memset(&request, 0, sizeof(request));
! 1768:
! 1769: DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}",
! 1770: ntohl(id->spi), data->reqid);
! 1771:
! 1772: msg = (struct sadb_msg*)request;
! 1773: msg->sadb_msg_version = PF_KEY_V2;
! 1774: msg->sadb_msg_type = SADB_ADD;
! 1775: msg->sadb_msg_satype = proto2satype(id->proto);
! 1776: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 1777:
! 1778: #ifdef __APPLE__
! 1779: if (data->encap)
! 1780: {
! 1781: struct sadb_sa_2 *sa_2;
! 1782: sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg);
! 1783: sa_2->sadb_sa_natt_port = id->dst->get_port(id->dst);
! 1784: sa = &sa_2->sa;
! 1785: sa->sadb_sa_flags |= SADB_X_EXT_NATT;
! 1786: len = sizeof(struct sadb_sa_2);
! 1787: }
! 1788: else
! 1789: #endif
! 1790: {
! 1791: sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
! 1792: len = sizeof(struct sadb_sa);
! 1793: }
! 1794: sa->sadb_sa_exttype = SADB_EXT_SA;
! 1795: sa->sadb_sa_len = PFKEY_LEN(len);
! 1796: sa->sadb_sa_spi = id->spi;
! 1797: sa->sadb_sa_state = SADB_SASTATE_MATURE;
! 1798: if (id->proto == IPPROTO_COMP)
! 1799: {
! 1800: sa->sadb_sa_encrypt = lookup_algorithm(COMPRESSION_ALGORITHM,
! 1801: ipcomp);
! 1802: }
! 1803: else
! 1804: {
! 1805: /* Linux interprets sadb_sa_replay as number of packets/bits in the
! 1806: * replay window, whereas on BSD it's the size of the window in bytes.
! 1807: * Only set for the inbound SA as it's not relevant for the outbound
! 1808: * SA and might waste memory with large windows. */
! 1809: if (data->inbound)
! 1810: {
! 1811: #ifdef __linux__
! 1812: sa->sadb_sa_replay = min(data->replay_window, 32);
! 1813: #else
! 1814: sa->sadb_sa_replay = min((data->replay_window + 7) / 8, UINT8_MAX);
! 1815: #endif
! 1816: }
! 1817: if (data->esn)
! 1818: {
! 1819: #ifdef SADB_X_SAFLAGS_ESN
! 1820: DBG2(DBG_KNL, " using extended sequence numbers (ESN)");
! 1821: sa->sadb_sa_flags |= SADB_X_SAFLAGS_ESN;
! 1822: #else
! 1823: DBG1(DBG_KNL, "extended sequence numbers (ESN) not supported by "
! 1824: "kernel!");
! 1825: return FAILED;
! 1826: #endif
! 1827: }
! 1828: sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, data->int_alg);
! 1829: sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM,
! 1830: data->enc_alg);
! 1831: }
! 1832: PFKEY_EXT_ADD(msg, sa);
! 1833:
! 1834: #ifdef SADB_X_EXT_SA_REPLAY
! 1835: if (data->inbound)
! 1836: {
! 1837: struct sadb_x_sa_replay *repl;
! 1838:
! 1839: repl = (struct sadb_x_sa_replay*)PFKEY_EXT_ADD_NEXT(msg);
! 1840: repl->sadb_x_sa_replay_exttype = SADB_X_EXT_SA_REPLAY;
! 1841: repl->sadb_x_sa_replay_len = PFKEY_LEN(sizeof(struct sadb_x_sa_replay));
! 1842: repl->sadb_x_sa_replay_replay = min(data->replay_window, UINT32_MAX-32);
! 1843: PFKEY_EXT_ADD(msg, repl);
! 1844: }
! 1845: #endif
! 1846:
! 1847: sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg);
! 1848: sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
! 1849: sa2->sadb_x_sa2_len = PFKEY_LEN(sizeof(struct sadb_spirange));
! 1850: sa2->sadb_x_sa2_mode = mode2kernel(mode);
! 1851: sa2->sadb_x_sa2_reqid = data->reqid;
! 1852: PFKEY_EXT_ADD(msg, sa2);
! 1853:
! 1854: add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE);
! 1855: add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
! 1856:
! 1857: lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg);
! 1858: lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
! 1859: lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime));
! 1860: lft->sadb_lifetime_allocations = data->lifetime->packets.rekey;
! 1861: lft->sadb_lifetime_bytes = data->lifetime->bytes.rekey;
! 1862: lft->sadb_lifetime_addtime = data->lifetime->time.rekey;
! 1863: lft->sadb_lifetime_usetime = 0; /* we only use addtime */
! 1864: PFKEY_EXT_ADD(msg, lft);
! 1865:
! 1866: lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg);
! 1867: lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
! 1868: lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime));
! 1869: lft->sadb_lifetime_allocations = data->lifetime->packets.life;
! 1870: lft->sadb_lifetime_bytes = data->lifetime->bytes.life;
! 1871: lft->sadb_lifetime_addtime = data->lifetime->time.life;
! 1872: lft->sadb_lifetime_usetime = 0; /* we only use addtime */
! 1873: PFKEY_EXT_ADD(msg, lft);
! 1874:
! 1875: if (data->enc_alg != ENCR_UNDEFINED)
! 1876: {
! 1877: if (!sa->sadb_sa_encrypt)
! 1878: {
! 1879: DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
! 1880: encryption_algorithm_names, data->enc_alg);
! 1881: return FAILED;
! 1882: }
! 1883: DBG2(DBG_KNL, " using encryption algorithm %N with key size %d",
! 1884: encryption_algorithm_names, data->enc_alg, data->enc_key.len * 8);
! 1885:
! 1886: key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
! 1887: key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
! 1888: key->sadb_key_bits = data->enc_key.len * 8;
! 1889: key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->enc_key.len);
! 1890: memcpy(key + 1, data->enc_key.ptr, data->enc_key.len);
! 1891:
! 1892: PFKEY_EXT_ADD(msg, key);
! 1893: }
! 1894:
! 1895: if (data->int_alg != AUTH_UNDEFINED)
! 1896: {
! 1897: if (!sa->sadb_sa_auth)
! 1898: {
! 1899: DBG1(DBG_KNL, "algorithm %N not supported by kernel!",
! 1900: integrity_algorithm_names, data->int_alg);
! 1901: return FAILED;
! 1902: }
! 1903: DBG2(DBG_KNL, " using integrity algorithm %N with key size %d",
! 1904: integrity_algorithm_names, data->int_alg, data->int_key.len * 8);
! 1905:
! 1906: key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg);
! 1907: key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
! 1908: key->sadb_key_bits = data->int_key.len * 8;
! 1909: key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + data->int_key.len);
! 1910: memcpy(key + 1, data->int_key.ptr, data->int_key.len);
! 1911:
! 1912: PFKEY_EXT_ADD(msg, key);
! 1913: }
! 1914:
! 1915: #ifdef HAVE_NATT
! 1916: if (data->encap)
! 1917: {
! 1918: add_encap_ext(msg, id->src, id->dst);
! 1919: }
! 1920: #endif /*HAVE_NATT*/
! 1921:
! 1922: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 1923: {
! 1924: DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x",
! 1925: ntohl(id->spi));
! 1926: return FAILED;
! 1927: }
! 1928: else if (out->sadb_msg_errno)
! 1929: {
! 1930: DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x: %s (%d)",
! 1931: ntohl(id->spi), strerror(out->sadb_msg_errno),
! 1932: out->sadb_msg_errno);
! 1933: free(out);
! 1934: return FAILED;
! 1935: }
! 1936:
! 1937: free(out);
! 1938: return SUCCESS;
! 1939: }
! 1940:
! 1941: METHOD(kernel_ipsec_t, update_sa, status_t,
! 1942: private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
! 1943: kernel_ipsec_update_sa_t *data)
! 1944: {
! 1945: unsigned char request[PFKEY_BUFFER_SIZE];
! 1946: struct sadb_msg *msg, *out;
! 1947: struct sadb_sa *sa;
! 1948: pfkey_msg_t response;
! 1949: size_t len;
! 1950:
! 1951: #ifndef SADB_X_EXT_NEW_ADDRESS_SRC
! 1952: /* we can't update the SA if any of the ip addresses have changed.
! 1953: * that's because we can't use SADB_UPDATE and by deleting and readding the
! 1954: * SA the sequence numbers would get lost */
! 1955: if (!id->src->ip_equals(id->src, data->new_src) ||
! 1956: !id->dst->ip_equals(id->dst, data->new_dst))
! 1957: {
! 1958: DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: address "
! 1959: "changes are not supported", ntohl(id->spi));
! 1960: return NOT_SUPPORTED;
! 1961: }
! 1962: #endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/
! 1963:
! 1964: /* if IPComp is used, we first update the IPComp SA */
! 1965: if (data->cpi)
! 1966: {
! 1967: kernel_ipsec_sa_id_t ipcomp_id = {
! 1968: .src = id->src,
! 1969: .dst = id->dst,
! 1970: .spi = htonl(ntohs(data->cpi)),
! 1971: .proto = IPPROTO_COMP,
! 1972: .mark = id->mark,
! 1973: };
! 1974: kernel_ipsec_update_sa_t ipcomp = {
! 1975: .new_src = data->new_src,
! 1976: .new_dst = data->new_dst,
! 1977: };
! 1978: update_sa(this, &ipcomp_id, &ipcomp);
! 1979: }
! 1980:
! 1981: memset(&request, 0, sizeof(request));
! 1982:
! 1983: DBG2(DBG_KNL, "querying SAD entry with SPI %.8x for update",
! 1984: ntohl(id->spi));
! 1985:
! 1986: msg = (struct sadb_msg*)request;
! 1987: msg->sadb_msg_version = PF_KEY_V2;
! 1988: msg->sadb_msg_type = SADB_GET;
! 1989: msg->sadb_msg_satype = proto2satype(id->proto);
! 1990: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 1991:
! 1992: sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
! 1993: sa->sadb_sa_exttype = SADB_EXT_SA;
! 1994: sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
! 1995: sa->sadb_sa_spi = id->spi;
! 1996: sa->sadb_sa_state = SADB_SASTATE_MATURE;
! 1997: PFKEY_EXT_ADD(msg, sa);
! 1998:
! 1999: add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE);
! 2000: add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
! 2001:
! 2002: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 2003: {
! 2004: DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x",
! 2005: ntohl(id->spi));
! 2006: return FAILED;
! 2007: }
! 2008: else if (out->sadb_msg_errno)
! 2009: {
! 2010: DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)",
! 2011: ntohl(id->spi), strerror(out->sadb_msg_errno),
! 2012: out->sadb_msg_errno);
! 2013: free(out);
! 2014: return FAILED;
! 2015: }
! 2016: else if (parse_pfkey_message(out, &response) != SUCCESS)
! 2017: {
! 2018: DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: parsing "
! 2019: "response from kernel failed", ntohl(id->spi));
! 2020: free(out);
! 2021: return FAILED;
! 2022: }
! 2023:
! 2024: DBG2(DBG_KNL, "updating SAD entry with SPI %.8x from %#H..%#H to %#H..%#H",
! 2025: ntohl(id->spi), id->src, id->dst, data->new_src, data->new_dst);
! 2026:
! 2027: memset(&request, 0, sizeof(request));
! 2028:
! 2029: msg = (struct sadb_msg*)request;
! 2030: msg->sadb_msg_version = PF_KEY_V2;
! 2031: msg->sadb_msg_type = SADB_UPDATE;
! 2032: msg->sadb_msg_satype = proto2satype(id->proto);
! 2033: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 2034:
! 2035: #ifdef __APPLE__
! 2036: {
! 2037: struct sadb_sa_2 *sa_2;
! 2038: sa_2 = (struct sadb_sa_2*)PFKEY_EXT_ADD_NEXT(msg);
! 2039: sa_2->sa.sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa_2));
! 2040: memcpy(&sa_2->sa, response.sa, sizeof(struct sadb_sa));
! 2041: if (data->new_encap)
! 2042: {
! 2043: sa_2->sadb_sa_natt_port = data->new_dst->get_port(data->new_dst);
! 2044: sa_2->sa.sadb_sa_flags |= SADB_X_EXT_NATT;
! 2045: }
! 2046: }
! 2047: #else
! 2048: PFKEY_EXT_COPY(msg, response.sa);
! 2049: #endif
! 2050: PFKEY_EXT_COPY(msg, response.x_sa2);
! 2051:
! 2052: PFKEY_EXT_COPY(msg, response.src);
! 2053: PFKEY_EXT_COPY(msg, response.dst);
! 2054:
! 2055: PFKEY_EXT_COPY(msg, response.lft_soft);
! 2056: PFKEY_EXT_COPY(msg, response.lft_hard);
! 2057:
! 2058: #ifndef __FreeBSD__
! 2059: /* FreeBSD 11.1 does not allow key updates via SADB_UPDATE for mature SAs */
! 2060: if (response.key_encr)
! 2061: {
! 2062: PFKEY_EXT_COPY(msg, response.key_encr);
! 2063: }
! 2064:
! 2065: if (response.key_auth)
! 2066: {
! 2067: PFKEY_EXT_COPY(msg, response.key_auth);
! 2068: }
! 2069: #endif
! 2070:
! 2071: #ifdef HAVE_NATT
! 2072: if (data->new_encap)
! 2073: {
! 2074: add_encap_ext(msg, data->new_src, data->new_dst);
! 2075: }
! 2076: #endif /*HAVE_NATT*/
! 2077:
! 2078: #ifdef SADB_X_EXT_NEW_ADDRESS_SRC
! 2079: if (!id->src->ip_equals(id->src, data->new_src))
! 2080: {
! 2081: add_addr_ext(msg, data->new_src, SADB_X_EXT_NEW_ADDRESS_SRC, 0, 0,
! 2082: FALSE);
! 2083: }
! 2084: if (!id->dst->ip_equals(id->dst, data->new_dst))
! 2085: {
! 2086: add_addr_ext(msg, data->new_dst, SADB_X_EXT_NEW_ADDRESS_DST, 0, 0,
! 2087: FALSE);
! 2088: }
! 2089: #endif /*SADB_X_EXT_NEW_ADDRESS_SRC*/
! 2090:
! 2091: free(out);
! 2092:
! 2093: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 2094: {
! 2095: DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x",
! 2096: ntohl(id->spi));
! 2097: return FAILED;
! 2098: }
! 2099: else if (out->sadb_msg_errno)
! 2100: {
! 2101: DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x: %s (%d)",
! 2102: ntohl(id->spi), strerror(out->sadb_msg_errno), out->sadb_msg_errno);
! 2103: free(out);
! 2104: return FAILED;
! 2105: }
! 2106: free(out);
! 2107:
! 2108: return SUCCESS;
! 2109: }
! 2110:
! 2111: METHOD(kernel_ipsec_t, query_sa, status_t,
! 2112: private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
! 2113: kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
! 2114: time_t *time)
! 2115: {
! 2116: unsigned char request[PFKEY_BUFFER_SIZE];
! 2117: struct sadb_msg *msg, *out;
! 2118: struct sadb_sa *sa;
! 2119: pfkey_msg_t response;
! 2120: size_t len;
! 2121:
! 2122: memset(&request, 0, sizeof(request));
! 2123:
! 2124: DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(id->spi));
! 2125:
! 2126: msg = (struct sadb_msg*)request;
! 2127: msg->sadb_msg_version = PF_KEY_V2;
! 2128: msg->sadb_msg_type = SADB_GET;
! 2129: msg->sadb_msg_satype = proto2satype(id->proto);
! 2130: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 2131:
! 2132: sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
! 2133: sa->sadb_sa_exttype = SADB_EXT_SA;
! 2134: sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
! 2135: sa->sadb_sa_spi = id->spi;
! 2136: PFKEY_EXT_ADD(msg, sa);
! 2137:
! 2138: /* the Linux Kernel doesn't care for the src address, but other systems do
! 2139: * (e.g. FreeBSD)
! 2140: */
! 2141: add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE);
! 2142: add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
! 2143:
! 2144: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 2145: {
! 2146: DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x",
! 2147: ntohl(id->spi));
! 2148: return FAILED;
! 2149: }
! 2150: else if (out->sadb_msg_errno)
! 2151: {
! 2152: DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x: %s (%d)",
! 2153: ntohl(id->spi), strerror(out->sadb_msg_errno),
! 2154: out->sadb_msg_errno);
! 2155: free(out);
! 2156: return FAILED;
! 2157: }
! 2158: else if (parse_pfkey_message(out, &response) != SUCCESS)
! 2159: {
! 2160: DBG1(DBG_KNL, "unable to query SAD entry with SPI %.8x",
! 2161: ntohl(id->spi));
! 2162: free(out);
! 2163: return FAILED;
! 2164: }
! 2165: if (bytes)
! 2166: {
! 2167: *bytes = response.lft_current->sadb_lifetime_bytes;
! 2168: }
! 2169: if (packets)
! 2170: {
! 2171: /* at least on Linux and FreeBSD this contains the number of packets */
! 2172: *packets = response.lft_current->sadb_lifetime_allocations;
! 2173: }
! 2174: if (time)
! 2175: {
! 2176: #ifdef __APPLE__
! 2177: /* OS X uses the "last" time of use in usetime */
! 2178: *time = response.lft_current->sadb_lifetime_usetime;
! 2179: #else /* !__APPLE__ */
! 2180: /* on Linux, sadb_lifetime_usetime is set to the "first" time of use,
! 2181: * which is actually correct according to PF_KEY. We have to query
! 2182: * policies for the last usetime. */
! 2183: *time = 0;
! 2184: #endif /* !__APPLE__ */
! 2185: }
! 2186:
! 2187: free(out);
! 2188: return SUCCESS;
! 2189: }
! 2190:
! 2191: METHOD(kernel_ipsec_t, del_sa, status_t,
! 2192: private_kernel_pfkey_ipsec_t *this, kernel_ipsec_sa_id_t *id,
! 2193: kernel_ipsec_del_sa_t *data)
! 2194: {
! 2195: unsigned char request[PFKEY_BUFFER_SIZE];
! 2196: struct sadb_msg *msg, *out;
! 2197: struct sadb_sa *sa;
! 2198: size_t len;
! 2199:
! 2200: /* if IPComp was used, we first delete the additional IPComp SA */
! 2201: if (data->cpi)
! 2202: {
! 2203: kernel_ipsec_sa_id_t ipcomp_id = {
! 2204: .src = id->src,
! 2205: .dst = id->dst,
! 2206: .spi = htonl(ntohs(data->cpi)),
! 2207: .proto = IPPROTO_COMP,
! 2208: .mark = id->mark,
! 2209: };
! 2210: kernel_ipsec_del_sa_t ipcomp = { 0 };
! 2211: del_sa(this, &ipcomp_id, &ipcomp);
! 2212: }
! 2213:
! 2214: memset(&request, 0, sizeof(request));
! 2215:
! 2216: DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(id->spi));
! 2217:
! 2218: msg = (struct sadb_msg*)request;
! 2219: msg->sadb_msg_version = PF_KEY_V2;
! 2220: msg->sadb_msg_type = SADB_DELETE;
! 2221: msg->sadb_msg_satype = proto2satype(id->proto);
! 2222: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 2223:
! 2224: sa = (struct sadb_sa*)PFKEY_EXT_ADD_NEXT(msg);
! 2225: sa->sadb_sa_exttype = SADB_EXT_SA;
! 2226: sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
! 2227: sa->sadb_sa_spi = id->spi;
! 2228: PFKEY_EXT_ADD(msg, sa);
! 2229:
! 2230: /* the Linux Kernel doesn't care for the src address, but other systems do
! 2231: * (e.g. FreeBSD)
! 2232: */
! 2233: add_addr_ext(msg, id->src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE);
! 2234: add_addr_ext(msg, id->dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE);
! 2235:
! 2236: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 2237: {
! 2238: DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x",
! 2239: ntohl(id->spi));
! 2240: return FAILED;
! 2241: }
! 2242: else if (out->sadb_msg_errno)
! 2243: {
! 2244: DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x: %s (%d)",
! 2245: ntohl(id->spi), strerror(out->sadb_msg_errno),
! 2246: out->sadb_msg_errno);
! 2247: free(out);
! 2248: return FAILED;
! 2249: }
! 2250:
! 2251: DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(id->spi));
! 2252: free(out);
! 2253: return SUCCESS;
! 2254: }
! 2255:
! 2256: METHOD(kernel_ipsec_t, flush_sas, status_t,
! 2257: private_kernel_pfkey_ipsec_t *this)
! 2258: {
! 2259: unsigned char request[PFKEY_BUFFER_SIZE];
! 2260: struct sadb_msg *msg, *out;
! 2261: struct {
! 2262: uint8_t proto;
! 2263: char *name;
! 2264: } protos[] = {
! 2265: { SADB_SATYPE_AH, "AH" },
! 2266: { SADB_SATYPE_ESP, "ESP" },
! 2267: { SADB_X_SATYPE_IPCOMP, "IPComp" },
! 2268: };
! 2269: size_t len;
! 2270: int i;
! 2271:
! 2272: memset(&request, 0, sizeof(request));
! 2273:
! 2274: msg = (struct sadb_msg*)request;
! 2275: msg->sadb_msg_version = PF_KEY_V2;
! 2276: msg->sadb_msg_type = SADB_FLUSH;
! 2277: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 2278:
! 2279: for (i = 0; i < countof(protos); i++)
! 2280: {
! 2281: DBG2(DBG_KNL, "flushing all %s SAD entries", protos[i].name);
! 2282:
! 2283: msg->sadb_msg_satype = protos[i].proto;
! 2284: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 2285: {
! 2286: DBG1(DBG_KNL, "unable to flush %s SAD entries", protos[i].name);
! 2287: return FAILED;
! 2288: }
! 2289: else if (out->sadb_msg_errno)
! 2290: {
! 2291: DBG1(DBG_KNL, "unable to flush %s SAD entries: %s (%d)",
! 2292: protos[i].name, strerror(out->sadb_msg_errno),
! 2293: out->sadb_msg_errno);
! 2294: free(out);
! 2295: return FAILED;
! 2296: }
! 2297: free(out);
! 2298: }
! 2299: return SUCCESS;
! 2300: }
! 2301:
! 2302: /**
! 2303: * Add an explicit exclude route to a routing entry
! 2304: */
! 2305: static void add_exclude_route(private_kernel_pfkey_ipsec_t *this,
! 2306: route_entry_t *route, host_t *src, host_t *dst)
! 2307: {
! 2308: enumerator_t *enumerator;
! 2309: exclude_route_t *exclude;
! 2310: host_t *gtw;
! 2311:
! 2312: enumerator = this->excludes->create_enumerator(this->excludes);
! 2313: while (enumerator->enumerate(enumerator, &exclude))
! 2314: {
! 2315: if (dst->ip_equals(dst, exclude->dst))
! 2316: {
! 2317: route->exclude = exclude;
! 2318: exclude->refs++;
! 2319: }
! 2320: }
! 2321: enumerator->destroy(enumerator);
! 2322:
! 2323: if (!route->exclude)
! 2324: {
! 2325: DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src);
! 2326: gtw = charon->kernel->get_nexthop(charon->kernel, dst, -1, NULL, NULL);
! 2327: if (gtw)
! 2328: {
! 2329: char *if_name = NULL;
! 2330:
! 2331: if (charon->kernel->get_interface(charon->kernel, src, &if_name) &&
! 2332: charon->kernel->add_route(charon->kernel,
! 2333: dst->get_address(dst),
! 2334: dst->get_family(dst) == AF_INET ? 32 : 128,
! 2335: gtw, src, if_name, FALSE) == SUCCESS)
! 2336: {
! 2337: INIT(exclude,
! 2338: .dst = dst->clone(dst),
! 2339: .src = src->clone(src),
! 2340: .gtw = gtw->clone(gtw),
! 2341: .refs = 1,
! 2342: );
! 2343: route->exclude = exclude;
! 2344: this->excludes->insert_last(this->excludes, exclude);
! 2345: }
! 2346: else
! 2347: {
! 2348: DBG1(DBG_KNL, "installing exclude route for %H failed", dst);
! 2349: }
! 2350: gtw->destroy(gtw);
! 2351: free(if_name);
! 2352: }
! 2353: else
! 2354: {
! 2355: DBG1(DBG_KNL, "gateway lookup for for %H failed", dst);
! 2356: }
! 2357: }
! 2358: }
! 2359:
! 2360: /**
! 2361: * Remove an exclude route attached to a routing entry
! 2362: */
! 2363: static void remove_exclude_route(private_kernel_pfkey_ipsec_t *this,
! 2364: route_entry_t *route)
! 2365: {
! 2366: if (route->exclude)
! 2367: {
! 2368: enumerator_t *enumerator;
! 2369: exclude_route_t *exclude;
! 2370: bool removed = FALSE;
! 2371: host_t *dst;
! 2372:
! 2373: enumerator = this->excludes->create_enumerator(this->excludes);
! 2374: while (enumerator->enumerate(enumerator, &exclude))
! 2375: {
! 2376: if (route->exclude == exclude)
! 2377: {
! 2378: if (--exclude->refs == 0)
! 2379: {
! 2380: this->excludes->remove_at(this->excludes, enumerator);
! 2381: removed = TRUE;
! 2382: break;
! 2383: }
! 2384: }
! 2385: }
! 2386: enumerator->destroy(enumerator);
! 2387:
! 2388: if (removed)
! 2389: {
! 2390: char *if_name = NULL;
! 2391:
! 2392: dst = route->exclude->dst;
! 2393: DBG2(DBG_KNL, "uninstalling exclude route for %H src %H",
! 2394: dst, route->exclude->src);
! 2395: if (charon->kernel->get_interface(
! 2396: charon->kernel,
! 2397: route->exclude->src, &if_name) &&
! 2398: charon->kernel->del_route(charon->kernel,
! 2399: dst->get_address(dst),
! 2400: dst->get_family(dst) == AF_INET ? 32 : 128,
! 2401: route->exclude->gtw, route->exclude->src,
! 2402: if_name, FALSE) != SUCCESS)
! 2403: {
! 2404: DBG1(DBG_KNL, "uninstalling exclude route for %H failed", dst);
! 2405: }
! 2406: exclude_route_destroy(route->exclude);
! 2407: free(if_name);
! 2408: }
! 2409: route->exclude = NULL;
! 2410: }
! 2411: }
! 2412:
! 2413: /**
! 2414: * Try to install a route to the given outbound policy
! 2415: */
! 2416: static bool install_route(private_kernel_pfkey_ipsec_t *this,
! 2417: policy_entry_t *policy, policy_sa_out_t *out)
! 2418: {
! 2419: route_entry_t *route, *old;
! 2420: host_t *host, *src, *dst;
! 2421: bool is_virtual;
! 2422:
! 2423: if (charon->kernel->get_address_by_ts(charon->kernel, out->src_ts, &host,
! 2424: &is_virtual) != SUCCESS)
! 2425: {
! 2426: return FALSE;
! 2427: }
! 2428:
! 2429: INIT(route,
! 2430: .prefixlen = policy->dst.mask,
! 2431: .src_ip = host,
! 2432: .dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net)),
! 2433: );
! 2434:
! 2435: src = out->generic.sa->src;
! 2436: dst = out->generic.sa->dst;
! 2437:
! 2438: if (!dst->is_anyaddr(dst))
! 2439: {
! 2440: route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1,
! 2441: src, &route->if_name);
! 2442:
! 2443: /* if the IP is virtual, we install the route over the interface it has
! 2444: * been installed on. Otherwise we use the interface we use for IKE, as
! 2445: * this is required for example on Linux. */
! 2446: if (is_virtual || this->route_via_internal)
! 2447: {
! 2448: free(route->if_name);
! 2449: route->if_name = NULL;
! 2450: src = route->src_ip;
! 2451: }
! 2452: }
! 2453: else
! 2454: { /* for shunt policies */
! 2455: route->gateway = charon->kernel->get_nexthop(charon->kernel,
! 2456: policy->dst.net, policy->dst.mask,
! 2457: route->src_ip, &route->if_name);
! 2458:
! 2459: /* we don't have a source address, use the address we found */
! 2460: src = route->src_ip;
! 2461: }
! 2462:
! 2463: /* get interface for route, using source address */
! 2464: if (!route->if_name &&
! 2465: !charon->kernel->get_interface(charon->kernel, src, &route->if_name))
! 2466: {
! 2467: route_entry_destroy(route);
! 2468: return FALSE;
! 2469: }
! 2470:
! 2471: if (policy->route)
! 2472: {
! 2473: old = policy->route;
! 2474:
! 2475: if (route_entry_equals(old, route))
! 2476: { /* such a route already exists */
! 2477: route_entry_destroy(route);
! 2478: return TRUE;
! 2479: }
! 2480: /* uninstall previously installed route */
! 2481: if (charon->kernel->del_route(charon->kernel, old->dst_net,
! 2482: old->prefixlen, old->gateway,
! 2483: old->src_ip, old->if_name, FALSE) != SUCCESS)
! 2484: {
! 2485: DBG1(DBG_KNL, "error uninstalling route installed with policy "
! 2486: "%R === %R %N", out->src_ts, out->dst_ts,
! 2487: policy_dir_names, policy->direction);
! 2488: }
! 2489: route_entry_destroy(old);
! 2490: policy->route = NULL;
! 2491: }
! 2492:
! 2493: /* if remote traffic selector covers the IKE peer, add an exclude route */
! 2494: if (charon->kernel->get_features(charon->kernel) & KERNEL_REQUIRE_EXCLUDE_ROUTE)
! 2495: {
! 2496: if (out->dst_ts->is_host(out->dst_ts, dst))
! 2497: {
! 2498: DBG1(DBG_KNL, "can't install route for %R === %R %N, conflicts "
! 2499: "with IKE traffic", out->src_ts, out->dst_ts, policy_dir_names,
! 2500: policy->direction);
! 2501: route_entry_destroy(route);
! 2502: return FALSE;
! 2503: }
! 2504: if (out->dst_ts->includes(out->dst_ts, dst))
! 2505: {
! 2506: add_exclude_route(this, route, out->generic.sa->src, dst);
! 2507: }
! 2508: }
! 2509:
! 2510: DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s",
! 2511: out->dst_ts, route->gateway, route->src_ip, route->if_name);
! 2512:
! 2513: switch (charon->kernel->add_route(charon->kernel, route->dst_net,
! 2514: route->prefixlen, route->gateway,
! 2515: route->src_ip, route->if_name, FALSE))
! 2516: {
! 2517: case ALREADY_DONE:
! 2518: /* route exists, do not uninstall */
! 2519: remove_exclude_route(this, route);
! 2520: route_entry_destroy(route);
! 2521: return TRUE;
! 2522: case SUCCESS:
! 2523: /* cache the installed route */
! 2524: policy->route = route;
! 2525: return TRUE;
! 2526: default:
! 2527: DBG1(DBG_KNL, "installing route failed: %R via %H src %H dev %s",
! 2528: out->dst_ts, route->gateway, route->src_ip, route->if_name);
! 2529: remove_exclude_route(this, route);
! 2530: route_entry_destroy(route);
! 2531: return FALSE;
! 2532: }
! 2533: }
! 2534:
! 2535: /**
! 2536: * Check if any significant data has changed to warrant sending an update to
! 2537: * the kernel.
! 2538: */
! 2539: static bool policy_update_required(policy_sa_t *current, policy_sa_t *updated)
! 2540: {
! 2541: if (current->type != updated->type
! 2542: #ifdef HAVE_STRUCT_SADB_X_POLICY_SADB_X_POLICY_PRIORITY
! 2543: || current->priority != updated->priority
! 2544: #endif
! 2545: )
! 2546: {
! 2547: return TRUE;
! 2548: }
! 2549: if (current->type == POLICY_IPSEC)
! 2550: {
! 2551: ipsec_sa_cfg_t *cur = ¤t->sa->cfg, *upd = &updated->sa->cfg;
! 2552:
! 2553: /* we don't use ipsec_sa_cfg_equals() here as e.g. SPIs are not
! 2554: * relevant for this kernel interface, so we don't have to update the
! 2555: * policy during a rekeying */
! 2556: if (cur->mode != upd->mode ||
! 2557: cur->reqid != upd->reqid ||
! 2558: cur->esp.use != upd->esp.use ||
! 2559: cur->ah.use != upd->ah.use ||
! 2560: cur->ipcomp.transform != upd->ipcomp.transform)
! 2561: {
! 2562: return TRUE;
! 2563: }
! 2564: if (cur->mode == MODE_TUNNEL &&
! 2565: (!current->sa->src->ip_equals(current->sa->src, updated->sa->src) ||
! 2566: !current->sa->dst->ip_equals(current->sa->dst, updated->sa->dst)))
! 2567: {
! 2568: return TRUE;
! 2569: }
! 2570: }
! 2571: return FALSE;
! 2572: }
! 2573:
! 2574: /**
! 2575: * Add or update a policy in the kernel.
! 2576: *
! 2577: * Note: The mutex has to be locked when entering this function.
! 2578: */
! 2579: static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this,
! 2580: policy_entry_t *policy, policy_sa_t *mapping, bool update)
! 2581: {
! 2582: unsigned char request[PFKEY_BUFFER_SIZE];
! 2583: struct sadb_msg *msg, *out;
! 2584: struct sadb_x_policy *pol;
! 2585: struct sadb_x_ipsecrequest *req;
! 2586: ipsec_sa_t *ipsec = mapping->sa;
! 2587: pfkey_msg_t response;
! 2588: size_t len;
! 2589: ipsec_mode_t proto_mode;
! 2590: status_t status;
! 2591:
! 2592: memset(&request, 0, sizeof(request));
! 2593:
! 2594: msg = (struct sadb_msg*)request;
! 2595: msg->sadb_msg_version = PF_KEY_V2;
! 2596: msg->sadb_msg_type = update ? SADB_X_SPDUPDATE : SADB_X_SPDADD;
! 2597: msg->sadb_msg_satype = 0;
! 2598: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 2599:
! 2600: pol = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg);
! 2601: pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
! 2602: pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy));
! 2603: pol->sadb_x_policy_id = 0;
! 2604: pol->sadb_x_policy_dir = dir2kernel(policy->direction);
! 2605: pol->sadb_x_policy_type = type2kernel(mapping->type);
! 2606: #ifdef HAVE_STRUCT_SADB_X_POLICY_SADB_X_POLICY_PRIORITY
! 2607: pol->sadb_x_policy_priority = mapping->priority;
! 2608: #endif
! 2609:
! 2610: if (mapping->type == POLICY_IPSEC && ipsec->cfg.reqid)
! 2611: {
! 2612: /* one or more sadb_x_ipsecrequest extensions are added to the
! 2613: * sadb_x_policy extension */
! 2614: proto_mode = ipsec->cfg.mode;
! 2615:
! 2616: req = (struct sadb_x_ipsecrequest*)(pol + 1);
! 2617:
! 2618: if (ipsec->cfg.ipcomp.transform != IPCOMP_NONE)
! 2619: {
! 2620: req->sadb_x_ipsecrequest_proto = IPPROTO_COMP;
! 2621:
! 2622: /* !!! the length here MUST be in octets instead of 64 bit words */
! 2623: req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
! 2624: req->sadb_x_ipsecrequest_mode = mode2kernel(ipsec->cfg.mode);
! 2625: req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid;
! 2626: req->sadb_x_ipsecrequest_level = (policy->direction == POLICY_OUT) ?
! 2627: IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_USE;
! 2628: if (ipsec->cfg.mode == MODE_TUNNEL)
! 2629: {
! 2630: len = hostcpy(req + 1, ipsec->src, FALSE);
! 2631: req->sadb_x_ipsecrequest_len += len;
! 2632: len = hostcpy((char*)(req + 1) + len, ipsec->dst, FALSE);
! 2633: req->sadb_x_ipsecrequest_len += len;
! 2634: /* use transport mode for other SAs */
! 2635: proto_mode = MODE_TRANSPORT;
! 2636: }
! 2637:
! 2638: pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len);
! 2639: req = (struct sadb_x_ipsecrequest*)((char*)(req) +
! 2640: req->sadb_x_ipsecrequest_len);
! 2641: }
! 2642:
! 2643: req->sadb_x_ipsecrequest_proto = ipsec->cfg.esp.use ? IPPROTO_ESP
! 2644: : IPPROTO_AH;
! 2645: /* !!! the length here MUST be in octets instead of 64 bit words */
! 2646: req->sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
! 2647: req->sadb_x_ipsecrequest_mode = mode2kernel(proto_mode);
! 2648: req->sadb_x_ipsecrequest_reqid = ipsec->cfg.reqid;
! 2649: req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
! 2650: if (proto_mode == MODE_TUNNEL)
! 2651: {
! 2652: len = hostcpy(req + 1, ipsec->src, FALSE);
! 2653: req->sadb_x_ipsecrequest_len += len;
! 2654: len = hostcpy((char*)(req + 1) + len, ipsec->dst, FALSE);
! 2655: req->sadb_x_ipsecrequest_len += len;
! 2656: }
! 2657:
! 2658: pol->sadb_x_policy_len += PFKEY_LEN(req->sadb_x_ipsecrequest_len);
! 2659: }
! 2660: PFKEY_EXT_ADD(msg, pol);
! 2661:
! 2662: add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto,
! 2663: policy->src.mask, TRUE);
! 2664: add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto,
! 2665: policy->dst.mask, TRUE);
! 2666:
! 2667: #ifdef __FreeBSD__
! 2668: { /* on FreeBSD a lifetime has to be defined to be able to later query
! 2669: * the current use time. */
! 2670: struct sadb_lifetime *lft;
! 2671: lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg);
! 2672: lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
! 2673: lft->sadb_lifetime_len = PFKEY_LEN(sizeof(struct sadb_lifetime));
! 2674: lft->sadb_lifetime_addtime = LONG_MAX;
! 2675: PFKEY_EXT_ADD(msg, lft);
! 2676: }
! 2677: #endif
! 2678:
! 2679: this->mutex->unlock(this->mutex);
! 2680:
! 2681: status = pfkey_send(this, msg, &out, &len);
! 2682: if (status == SUCCESS && !update && out->sadb_msg_errno == EEXIST)
! 2683: {
! 2684: DBG1(DBG_KNL, "policy already exists, try to update it");
! 2685: free(out);
! 2686: msg->sadb_msg_type = SADB_X_SPDUPDATE;
! 2687: status = pfkey_send(this, msg, &out, &len);
! 2688: }
! 2689: if (status != SUCCESS)
! 2690: {
! 2691: return FAILED;
! 2692: }
! 2693: else if (out->sadb_msg_errno)
! 2694: {
! 2695: DBG1(DBG_KNL, "unable to %s policy: %s (%d)",
! 2696: update ? "update" : "add", strerror(out->sadb_msg_errno),
! 2697: out->sadb_msg_errno);
! 2698: free(out);
! 2699: return FAILED;
! 2700: }
! 2701: else if (parse_pfkey_message(out, &response) != SUCCESS)
! 2702: {
! 2703: DBG1(DBG_KNL, "unable to %s policy: parsing response from kernel "
! 2704: "failed", update ? "update" : "add");
! 2705: free(out);
! 2706: return FAILED;
! 2707: }
! 2708:
! 2709: /* we try to find the policy again and update the kernel index */
! 2710: this->mutex->lock(this->mutex);
! 2711: if (!this->policies->find_first(this->policies, NULL, (void**)&policy))
! 2712: {
! 2713: DBG2(DBG_KNL, "unable to update index, the policy is already gone, "
! 2714: "ignoring");
! 2715: this->mutex->unlock(this->mutex);
! 2716: free(out);
! 2717: return SUCCESS;
! 2718: }
! 2719: policy->index = response.x_policy->sadb_x_policy_id;
! 2720: free(out);
! 2721:
! 2722: /* install a route, if:
! 2723: * - this is an outbound policy (to just get one for each child)
! 2724: * - routing is not disabled via strongswan.conf
! 2725: * - the selector is not for a specific protocol/port
! 2726: * - we are in tunnel mode or install a bypass policy
! 2727: */
! 2728: if (policy->direction == POLICY_OUT && this->install_routes &&
! 2729: policy->src.proto == IPSEC_PROTO_ANY &&
! 2730: !policy->src.net->get_port(policy->src.net) &&
! 2731: !policy->dst.net->get_port(policy->dst.net))
! 2732: {
! 2733: if (mapping->type == POLICY_PASS ||
! 2734: (mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT))
! 2735: {
! 2736: install_route(this, policy, (policy_sa_out_t*)mapping);
! 2737: }
! 2738: }
! 2739: this->mutex->unlock(this->mutex);
! 2740: return SUCCESS;
! 2741: }
! 2742:
! 2743: METHOD(kernel_ipsec_t, add_policy, status_t,
! 2744: private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id,
! 2745: kernel_ipsec_manage_policy_t *data)
! 2746: {
! 2747: policy_entry_t *policy, *found = NULL;
! 2748: policy_sa_t *assigned_sa, *current_sa = NULL;
! 2749: enumerator_t *enumerator;
! 2750: bool update = TRUE;
! 2751:
! 2752: if (dir2kernel(id->dir) == IPSEC_DIR_INVALID)
! 2753: { /* FWD policies are not supported on all platforms */
! 2754: return SUCCESS;
! 2755: }
! 2756:
! 2757: /* create a policy */
! 2758: policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir);
! 2759:
! 2760: /* find a matching policy */
! 2761: this->mutex->lock(this->mutex);
! 2762: if (this->policies->find_first(this->policies, policy_entry_equals,
! 2763: (void**)&found, policy))
! 2764: { /* use existing policy */
! 2765: DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
! 2766: "refcount", id->src_ts, id->dst_ts, policy_dir_names, id->dir);
! 2767: policy_entry_destroy(policy, this);
! 2768: policy = found;
! 2769: }
! 2770: else
! 2771: { /* use the new one, if we have no such policy */
! 2772: this->policies->insert_first(this->policies, policy);
! 2773: policy->used_by = linked_list_create();
! 2774: }
! 2775:
! 2776: /* cache the assigned IPsec SA */
! 2777: assigned_sa = policy_sa_create(this, id->dir, data->type, data->src,
! 2778: data->dst, id->src_ts, id->dst_ts, data->sa);
! 2779: assigned_sa->auto_priority = get_priority(policy, data->prio);
! 2780: assigned_sa->priority = data->manual_prio ? data->manual_prio :
! 2781: assigned_sa->auto_priority;
! 2782:
! 2783:
! 2784: /* insert the SA according to its priority */
! 2785: enumerator = policy->used_by->create_enumerator(policy->used_by);
! 2786: while (enumerator->enumerate(enumerator, (void**)¤t_sa))
! 2787: {
! 2788: if (current_sa->priority > assigned_sa->priority)
! 2789: {
! 2790: break;
! 2791: }
! 2792: if (current_sa->priority == assigned_sa->priority)
! 2793: {
! 2794: /* in case of equal manual prios order SAs by automatic priority */
! 2795: if (current_sa->auto_priority > assigned_sa->auto_priority)
! 2796: {
! 2797: break;
! 2798: }
! 2799: /* prefer SAs with a reqid over those without */
! 2800: if (current_sa->auto_priority == assigned_sa->auto_priority &&
! 2801: (!current_sa->sa->cfg.reqid || assigned_sa->sa->cfg.reqid))
! 2802: {
! 2803: break;
! 2804: }
! 2805: }
! 2806: update = FALSE;
! 2807: }
! 2808: policy->used_by->insert_before(policy->used_by, enumerator, assigned_sa);
! 2809: enumerator->destroy(enumerator);
! 2810:
! 2811: if (update && current_sa)
! 2812: { /* check if there are actually any relevant changes, if not, we don't
! 2813: * send an update to the kernel as e.g. FreeBSD doesn't do that
! 2814: * atomically, causing unnecessary traffic loss during rekeyings */
! 2815: update = policy_update_required(current_sa, assigned_sa);
! 2816: }
! 2817:
! 2818: if (!update)
! 2819: { /* we don't update the policy if the priority is lower than that of the
! 2820: * currently installed one */
! 2821: this->mutex->unlock(this->mutex);
! 2822: return SUCCESS;
! 2823: }
! 2824:
! 2825: DBG2(DBG_KNL, "%s policy %R === %R %N",
! 2826: found ? "updating" : "adding", id->src_ts, id->dst_ts,
! 2827: policy_dir_names, id->dir);
! 2828:
! 2829: if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS)
! 2830: {
! 2831: DBG1(DBG_KNL, "unable to %s policy %R === %R %N",
! 2832: found ? "update" : "add", id->src_ts, id->dst_ts,
! 2833: policy_dir_names, id->dir);
! 2834: return FAILED;
! 2835: }
! 2836: return SUCCESS;
! 2837: }
! 2838:
! 2839: METHOD(kernel_ipsec_t, query_policy, status_t,
! 2840: private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id,
! 2841: kernel_ipsec_query_policy_t *data, time_t *use_time)
! 2842: {
! 2843: unsigned char request[PFKEY_BUFFER_SIZE];
! 2844: struct sadb_msg *msg, *out;
! 2845: struct sadb_x_policy *pol;
! 2846: policy_entry_t *policy, *found = NULL;
! 2847: pfkey_msg_t response;
! 2848: size_t len;
! 2849:
! 2850: if (dir2kernel(id->dir) == IPSEC_DIR_INVALID)
! 2851: { /* FWD policies are not supported on all platforms */
! 2852: return NOT_FOUND;
! 2853: }
! 2854:
! 2855: DBG2(DBG_KNL, "querying policy %R === %R %N", id->src_ts, id->dst_ts,
! 2856: policy_dir_names, id->dir);
! 2857:
! 2858: /* create a policy */
! 2859: policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir);
! 2860:
! 2861: /* find a matching policy */
! 2862: this->mutex->lock(this->mutex);
! 2863: if (!this->policies->find_first(this->policies, policy_entry_equals,
! 2864: (void**)&found, policy))
! 2865: {
! 2866: DBG1(DBG_KNL, "querying policy %R === %R %N failed, not found",
! 2867: id->src_ts, id->dst_ts, policy_dir_names, id->dir);
! 2868: policy_entry_destroy(policy, this);
! 2869: this->mutex->unlock(this->mutex);
! 2870: return NOT_FOUND;
! 2871: }
! 2872: policy_entry_destroy(policy, this);
! 2873: policy = found;
! 2874:
! 2875: memset(&request, 0, sizeof(request));
! 2876:
! 2877: msg = (struct sadb_msg*)request;
! 2878: msg->sadb_msg_version = PF_KEY_V2;
! 2879: msg->sadb_msg_type = SADB_X_SPDGET;
! 2880: msg->sadb_msg_satype = 0;
! 2881: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 2882:
! 2883: pol = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg);
! 2884: pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
! 2885: pol->sadb_x_policy_id = policy->index;
! 2886: pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy));
! 2887: pol->sadb_x_policy_dir = dir2kernel(id->dir);
! 2888: pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
! 2889: PFKEY_EXT_ADD(msg, pol);
! 2890:
! 2891: add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto,
! 2892: policy->src.mask, TRUE);
! 2893: add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto,
! 2894: policy->dst.mask, TRUE);
! 2895:
! 2896: this->mutex->unlock(this->mutex);
! 2897:
! 2898: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 2899: {
! 2900: DBG1(DBG_KNL, "unable to query policy %R === %R %N", id->src_ts,
! 2901: id->dst_ts, policy_dir_names, id->dir);
! 2902: return FAILED;
! 2903: }
! 2904: else if (out->sadb_msg_errno)
! 2905: {
! 2906: DBG1(DBG_KNL, "unable to query policy %R === %R %N: %s (%d)",
! 2907: id->src_ts, id->dst_ts, policy_dir_names, id->dir,
! 2908: strerror(out->sadb_msg_errno), out->sadb_msg_errno);
! 2909: free(out);
! 2910: return FAILED;
! 2911: }
! 2912: else if (parse_pfkey_message(out, &response) != SUCCESS)
! 2913: {
! 2914: DBG1(DBG_KNL, "unable to query policy %R === %R %N: parsing response "
! 2915: "from kernel failed", id->src_ts, id->dst_ts, policy_dir_names,
! 2916: id->dir);
! 2917: free(out);
! 2918: return FAILED;
! 2919: }
! 2920: else if (response.lft_current == NULL)
! 2921: {
! 2922: DBG2(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no "
! 2923: "use time", id->src_ts, id->dst_ts, policy_dir_names,
! 2924: id->dir);
! 2925: free(out);
! 2926: return FAILED;
! 2927: }
! 2928:
! 2929: /* we need the monotonic time, but the kernel returns system time. */
! 2930: if (response.lft_current->sadb_lifetime_usetime)
! 2931: {
! 2932: *use_time = time_monotonic(NULL) -
! 2933: (time(NULL) - response.lft_current->sadb_lifetime_usetime);
! 2934: }
! 2935: else
! 2936: {
! 2937: *use_time = 0;
! 2938: }
! 2939: free(out);
! 2940: return SUCCESS;
! 2941: }
! 2942:
! 2943: METHOD(kernel_ipsec_t, del_policy, status_t,
! 2944: private_kernel_pfkey_ipsec_t *this, kernel_ipsec_policy_id_t *id,
! 2945: kernel_ipsec_manage_policy_t *data)
! 2946: {
! 2947: unsigned char request[PFKEY_BUFFER_SIZE];
! 2948: struct sadb_msg *msg, *out;
! 2949: struct sadb_x_policy *pol;
! 2950: policy_entry_t *policy, *found = NULL;
! 2951: policy_sa_t *mapping, *to_remove = NULL;
! 2952: enumerator_t *enumerator;
! 2953: bool first = TRUE, is_installed = TRUE;
! 2954: uint32_t priority, auto_priority;
! 2955: size_t len;
! 2956: ipsec_sa_t assigned_sa = {
! 2957: .src = data->src,
! 2958: .dst = data->dst,
! 2959: .cfg = *data->sa,
! 2960: };
! 2961:
! 2962: if (dir2kernel(id->dir) == IPSEC_DIR_INVALID)
! 2963: { /* FWD policies are not supported on all platforms */
! 2964: return SUCCESS;
! 2965: }
! 2966:
! 2967: DBG2(DBG_KNL, "deleting policy %R === %R %N", id->src_ts, id->dst_ts,
! 2968: policy_dir_names, id->dir);
! 2969:
! 2970: /* create a policy */
! 2971: policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir);
! 2972:
! 2973: /* find a matching policy */
! 2974: this->mutex->lock(this->mutex);
! 2975: if (!this->policies->find_first(this->policies, policy_entry_equals,
! 2976: (void**)&found, policy))
! 2977: {
! 2978: DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found",
! 2979: id->src_ts, id->dst_ts, policy_dir_names, id->dir);
! 2980: policy_entry_destroy(policy, this);
! 2981: this->mutex->unlock(this->mutex);
! 2982: return NOT_FOUND;
! 2983: }
! 2984: policy_entry_destroy(policy, this);
! 2985: policy = found;
! 2986:
! 2987: /* remove mapping to SA by reqid and priority, if multiple match, which
! 2988: * could happen when rekeying due to an address change, remove the oldest */
! 2989: auto_priority = get_priority(policy, data->prio);
! 2990: priority = data->manual_prio ? data->manual_prio : auto_priority;
! 2991: enumerator = policy->used_by->create_enumerator(policy->used_by);
! 2992: while (enumerator->enumerate(enumerator, (void**)&mapping))
! 2993: {
! 2994: if (priority == mapping->priority &&
! 2995: auto_priority == mapping->auto_priority &&
! 2996: data->type == mapping->type &&
! 2997: ipsec_sa_equals(mapping->sa, &assigned_sa))
! 2998: {
! 2999: to_remove = mapping;
! 3000: is_installed = first;
! 3001: }
! 3002: else if (priority < mapping->priority)
! 3003: {
! 3004: break;
! 3005: }
! 3006: first = FALSE;
! 3007: }
! 3008: enumerator->destroy(enumerator);
! 3009: if (!to_remove)
! 3010: { /* sanity check */
! 3011: this->mutex->unlock(this->mutex);
! 3012: return SUCCESS;
! 3013: }
! 3014: policy->used_by->remove(policy->used_by, to_remove, NULL);
! 3015:
! 3016: if (policy->used_by->get_count(policy->used_by) > 0)
! 3017: { /* policy is used by more SAs, keep in kernel */
! 3018: DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
! 3019:
! 3020: if (is_installed)
! 3021: { /* check if there are actually any relevant changes, if not, we do
! 3022: * not send an update to the kernel as e.g. FreeBSD doesn't do that
! 3023: * atomically, causing unnecessary traffic loss during rekeyings */
! 3024: policy->used_by->get_first(policy->used_by, (void**)&mapping);
! 3025: is_installed = policy_update_required(mapping, to_remove);
! 3026: }
! 3027: policy_sa_destroy(to_remove, id->dir, this);
! 3028:
! 3029: if (!is_installed)
! 3030: { /* no need to update as the policy */
! 3031: this->mutex->unlock(this->mutex);
! 3032: return SUCCESS;
! 3033: }
! 3034:
! 3035: DBG2(DBG_KNL, "updating policy %R === %R %N", id->src_ts, id->dst_ts,
! 3036: policy_dir_names, id->dir);
! 3037: if (add_policy_internal(this, policy, mapping, TRUE) != SUCCESS)
! 3038: {
! 3039: DBG1(DBG_KNL, "unable to update policy %R === %R %N",
! 3040: id->src_ts, id->dst_ts, policy_dir_names, id->dir);
! 3041: return FAILED;
! 3042: }
! 3043: return SUCCESS;
! 3044: }
! 3045:
! 3046: memset(&request, 0, sizeof(request));
! 3047:
! 3048: msg = (struct sadb_msg*)request;
! 3049: msg->sadb_msg_version = PF_KEY_V2;
! 3050: msg->sadb_msg_type = SADB_X_SPDDELETE;
! 3051: msg->sadb_msg_satype = 0;
! 3052: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 3053:
! 3054: pol = (struct sadb_x_policy*)PFKEY_EXT_ADD_NEXT(msg);
! 3055: pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
! 3056: pol->sadb_x_policy_len = PFKEY_LEN(sizeof(struct sadb_x_policy));
! 3057: pol->sadb_x_policy_dir = dir2kernel(id->dir);
! 3058: pol->sadb_x_policy_type = type2kernel(to_remove->type);
! 3059: PFKEY_EXT_ADD(msg, pol);
! 3060:
! 3061: add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto,
! 3062: policy->src.mask, TRUE);
! 3063: add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto,
! 3064: policy->dst.mask, TRUE);
! 3065:
! 3066: if (policy->route)
! 3067: {
! 3068: route_entry_t *route = policy->route;
! 3069: if (charon->kernel->del_route(charon->kernel, route->dst_net,
! 3070: route->prefixlen, route->gateway,
! 3071: route->src_ip, route->if_name, FALSE) != SUCCESS)
! 3072: {
! 3073: DBG1(DBG_KNL, "error uninstalling route installed with "
! 3074: "policy %R === %R %N", id->src_ts, id->dst_ts,
! 3075: policy_dir_names, id->dir);
! 3076: }
! 3077: remove_exclude_route(this, route);
! 3078: }
! 3079:
! 3080: this->policies->remove(this->policies, found, NULL);
! 3081: policy_sa_destroy(to_remove, id->dir, this);
! 3082: policy_entry_destroy(policy, this);
! 3083: this->mutex->unlock(this->mutex);
! 3084:
! 3085: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 3086: {
! 3087: DBG1(DBG_KNL, "unable to delete policy %R === %R %N", id->src_ts,
! 3088: id->dst_ts, policy_dir_names, id->dir);
! 3089: return FAILED;
! 3090: }
! 3091: else if (out->sadb_msg_errno)
! 3092: {
! 3093: DBG1(DBG_KNL, "unable to delete policy %R === %R %N: %s (%d)",
! 3094: id->src_ts, id->dst_ts, policy_dir_names, id->dir,
! 3095: strerror(out->sadb_msg_errno), out->sadb_msg_errno);
! 3096: free(out);
! 3097: return FAILED;
! 3098: }
! 3099: free(out);
! 3100: return SUCCESS;
! 3101: }
! 3102:
! 3103: METHOD(kernel_ipsec_t, flush_policies, status_t,
! 3104: private_kernel_pfkey_ipsec_t *this)
! 3105: {
! 3106: unsigned char request[PFKEY_BUFFER_SIZE];
! 3107: struct sadb_msg *msg, *out;
! 3108: size_t len;
! 3109:
! 3110: memset(&request, 0, sizeof(request));
! 3111:
! 3112: DBG2(DBG_KNL, "flushing all policies from SPD");
! 3113:
! 3114: msg = (struct sadb_msg*)request;
! 3115: msg->sadb_msg_version = PF_KEY_V2;
! 3116: msg->sadb_msg_type = SADB_X_SPDFLUSH;
! 3117: msg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
! 3118: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 3119:
! 3120: if (pfkey_send(this, msg, &out, &len) != SUCCESS)
! 3121: {
! 3122: DBG1(DBG_KNL, "unable to flush SPD entries");
! 3123: return FAILED;
! 3124: }
! 3125: else if (out->sadb_msg_errno)
! 3126: {
! 3127: DBG1(DBG_KNL, "unable to flush SPD entries: %s (%d)",
! 3128: strerror(out->sadb_msg_errno), out->sadb_msg_errno);
! 3129: free(out);
! 3130: return FAILED;
! 3131: }
! 3132: free(out);
! 3133: return SUCCESS;
! 3134: }
! 3135:
! 3136: /**
! 3137: * Register a socket for ACQUIRE/EXPIRE messages
! 3138: */
! 3139: static status_t register_pfkey_socket(private_kernel_pfkey_ipsec_t *this,
! 3140: uint8_t satype)
! 3141: {
! 3142: unsigned char request[PFKEY_BUFFER_SIZE];
! 3143: struct sadb_msg *msg, *out;
! 3144: size_t len;
! 3145:
! 3146: memset(&request, 0, sizeof(request));
! 3147:
! 3148: msg = (struct sadb_msg*)request;
! 3149: msg->sadb_msg_version = PF_KEY_V2;
! 3150: msg->sadb_msg_type = SADB_REGISTER;
! 3151: msg->sadb_msg_satype = satype;
! 3152: msg->sadb_msg_len = PFKEY_LEN(sizeof(struct sadb_msg));
! 3153:
! 3154: if (pfkey_send_socket(this, this->socket_events, msg, &out, &len) != SUCCESS)
! 3155: {
! 3156: DBG1(DBG_KNL, "unable to register PF_KEY socket");
! 3157: return FAILED;
! 3158: }
! 3159: else if (out->sadb_msg_errno)
! 3160: {
! 3161: DBG1(DBG_KNL, "unable to register PF_KEY socket: %s (%d)",
! 3162: strerror(out->sadb_msg_errno), out->sadb_msg_errno);
! 3163: free(out);
! 3164: return FAILED;
! 3165: }
! 3166: free(out);
! 3167: return SUCCESS;
! 3168: }
! 3169:
! 3170: METHOD(kernel_ipsec_t, bypass_socket, bool,
! 3171: private_kernel_pfkey_ipsec_t *this, int fd, int family)
! 3172: {
! 3173: struct sadb_x_policy policy;
! 3174: u_int sol, ipsec_policy;
! 3175:
! 3176: switch (family)
! 3177: {
! 3178: case AF_INET:
! 3179: {
! 3180: sol = SOL_IP;
! 3181: ipsec_policy = IP_IPSEC_POLICY;
! 3182: break;
! 3183: }
! 3184: case AF_INET6:
! 3185: {
! 3186: sol = SOL_IPV6;
! 3187: ipsec_policy = IPV6_IPSEC_POLICY;
! 3188: break;
! 3189: }
! 3190: default:
! 3191: return FALSE;
! 3192: }
! 3193:
! 3194: memset(&policy, 0, sizeof(policy));
! 3195: policy.sadb_x_policy_len = sizeof(policy) / sizeof(uint64_t);
! 3196: policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
! 3197: policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
! 3198:
! 3199: policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
! 3200: if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
! 3201: {
! 3202: DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
! 3203: strerror(errno));
! 3204: return FALSE;
! 3205: }
! 3206: policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
! 3207: if (setsockopt(fd, sol, ipsec_policy, &policy, sizeof(policy)) < 0)
! 3208: {
! 3209: DBG1(DBG_KNL, "unable to set IPSEC_POLICY on socket: %s",
! 3210: strerror(errno));
! 3211: return FALSE;
! 3212: }
! 3213: return TRUE;
! 3214: }
! 3215:
! 3216: METHOD(kernel_ipsec_t, enable_udp_decap, bool,
! 3217: private_kernel_pfkey_ipsec_t *this, int fd, int family, uint16_t port)
! 3218: {
! 3219: #ifndef __APPLE__
! 3220: int type = UDP_ENCAP_ESPINUDP;
! 3221:
! 3222: if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0)
! 3223: {
! 3224: DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno));
! 3225: return FALSE;
! 3226: }
! 3227: #else /* __APPLE__ */
! 3228: int intport = port;
! 3229:
! 3230: if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &intport,
! 3231: sizeof(intport)) != 0)
! 3232: {
! 3233: DBG1(DBG_KNL, "could not set net.inet.ipsec.esp_port to %d: %s",
! 3234: port, strerror(errno));
! 3235: return FALSE;
! 3236: }
! 3237: #endif /* __APPLE__ */
! 3238:
! 3239: return TRUE;
! 3240: }
! 3241:
! 3242: METHOD(kernel_ipsec_t, destroy, void,
! 3243: private_kernel_pfkey_ipsec_t *this)
! 3244: {
! 3245: if (this->socket > 0)
! 3246: {
! 3247: close(this->socket);
! 3248: }
! 3249: if (this->socket_events > 0)
! 3250: {
! 3251: lib->watcher->remove(lib->watcher, this->socket_events);
! 3252: close(this->socket_events);
! 3253: }
! 3254: this->policies->invoke_function(this->policies, policy_entry_destroy_cb,
! 3255: this);
! 3256: this->policies->destroy(this->policies);
! 3257: this->excludes->destroy(this->excludes);
! 3258: this->sas->destroy(this->sas);
! 3259: this->mutex->destroy(this->mutex);
! 3260: this->mutex_pfkey->destroy(this->mutex_pfkey);
! 3261: free(this);
! 3262: }
! 3263:
! 3264: /*
! 3265: * Described in header.
! 3266: */
! 3267: kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create()
! 3268: {
! 3269: private_kernel_pfkey_ipsec_t *this;
! 3270: bool register_for_events = TRUE;
! 3271: int rcv_buffer;
! 3272:
! 3273: INIT(this,
! 3274: .public = {
! 3275: .interface = {
! 3276: .get_spi = _get_spi,
! 3277: .get_cpi = _get_cpi,
! 3278: .add_sa = _add_sa,
! 3279: .update_sa = _update_sa,
! 3280: .query_sa = _query_sa,
! 3281: .del_sa = _del_sa,
! 3282: .flush_sas = _flush_sas,
! 3283: .add_policy = _add_policy,
! 3284: .query_policy = _query_policy,
! 3285: .del_policy = _del_policy,
! 3286: .flush_policies = _flush_policies,
! 3287: .bypass_socket = _bypass_socket,
! 3288: .enable_udp_decap = _enable_udp_decap,
! 3289: .destroy = _destroy,
! 3290: },
! 3291: },
! 3292: .policies = linked_list_create(),
! 3293: .excludes = linked_list_create(),
! 3294: .sas = hashtable_create((hashtable_hash_t)ipsec_sa_hash,
! 3295: (hashtable_equals_t)ipsec_sa_equals, 32),
! 3296: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
! 3297: .mutex_pfkey = mutex_create(MUTEX_TYPE_DEFAULT),
! 3298: .install_routes = lib->settings->get_bool(lib->settings,
! 3299: "%s.install_routes", TRUE,
! 3300: lib->ns),
! 3301: .route_via_internal = lib->settings->get_bool(lib->settings,
! 3302: "%s.plugins.kernel-pfkey.route_via_internal",
! 3303: FALSE, lib->ns),
! 3304: );
! 3305:
! 3306: if (streq(lib->ns, "starter"))
! 3307: { /* starter has no threads, so we do not register for kernel events */
! 3308: register_for_events = FALSE;
! 3309: }
! 3310:
! 3311: /* create a PF_KEY socket to communicate with the kernel */
! 3312: this->socket = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
! 3313: if (this->socket <= 0)
! 3314: {
! 3315: DBG1(DBG_KNL, "unable to create PF_KEY socket");
! 3316: destroy(this);
! 3317: return NULL;
! 3318: }
! 3319:
! 3320: if (register_for_events)
! 3321: {
! 3322: /* create a PF_KEY socket for ACQUIRE & EXPIRE */
! 3323: this->socket_events = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
! 3324: if (this->socket_events <= 0)
! 3325: {
! 3326: DBG1(DBG_KNL, "unable to create PF_KEY event socket");
! 3327: destroy(this);
! 3328: return NULL;
! 3329: }
! 3330:
! 3331: rcv_buffer = lib->settings->get_int(lib->settings,
! 3332: "%s.plugins.kernel-pfkey.events_buffer_size", 0, lib->ns);
! 3333: if (rcv_buffer > 0)
! 3334: {
! 3335: if (setsockopt(this->socket_events, SOL_SOCKET, SO_RCVBUF,
! 3336: &rcv_buffer, sizeof(rcv_buffer)) == -1)
! 3337: {
! 3338: DBG1(DBG_KNL, "unable to set receive buffer size on PF_KEY "
! 3339: "event socket: %s", strerror(errno));
! 3340: }
! 3341: }
! 3342:
! 3343: /* register the event socket */
! 3344: if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS ||
! 3345: register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS)
! 3346: {
! 3347: DBG1(DBG_KNL, "unable to register PF_KEY event socket");
! 3348: destroy(this);
! 3349: return NULL;
! 3350: }
! 3351:
! 3352: lib->watcher->add(lib->watcher, this->socket_events, WATCHER_READ,
! 3353: (watcher_cb_t)receive_events, this);
! 3354: }
! 3355:
! 3356: return &this->public;
! 3357: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>