ipsec_policy_mgr.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. * Copyright (C) 2012 Tobias Brunner
  3. * Copyright (C) 2012 Giuliano Grassi
  4. * Copyright (C) 2012 Ralf Sager
  5. * HSR Hochschule fuer Technik Rapperswil
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2 of the License, or (at your
  10. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  14. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15. * for more details.
  16. */
  17. #include "ipsec_policy_mgr.h"
  18. #include <utils/debug.h>
  19. #include <threading/rwlock.h>
  20. #include <collections/linked_list.h>
  21. /** Base priority for installed policies */
  22. #define PRIO_BASE 384
  23. typedef struct private_ipsec_policy_mgr_t private_ipsec_policy_mgr_t;
  24. /**
  25. * Private additions to ipsec_policy_mgr_t.
  26. */
  27. struct private_ipsec_policy_mgr_t {
  28. /**
  29. * Public members of ipsec_policy_mgr_t.
  30. */
  31. ipsec_policy_mgr_t public;
  32. /**
  33. * Installed policies (ipsec_policy_entry_t*)
  34. */
  35. linked_list_t *policies;
  36. /**
  37. * Lock to safely access the list of policies
  38. */
  39. rwlock_t *lock;
  40. };
  41. /**
  42. * Helper struct to store policies in a list sorted by the same pseudo-priority
  43. * used by the NETLINK kernel interface.
  44. */
  45. typedef struct {
  46. /**
  47. * Priority used to sort policies
  48. */
  49. uint32_t priority;
  50. /**
  51. * The policy
  52. */
  53. ipsec_policy_t *policy;
  54. } ipsec_policy_entry_t;
  55. /**
  56. * Calculate the pseudo-priority to sort policies. This is the same algorithm
  57. * used by the NETLINK kernel interface (i.e. high priority -> low value).
  58. */
  59. static uint32_t calculate_priority(policy_priority_t policy_priority,
  60. traffic_selector_t *src,
  61. traffic_selector_t *dst)
  62. {
  63. uint32_t priority = PRIO_BASE;
  64. uint16_t port;
  65. uint8_t mask, proto;
  66. host_t *net;
  67. switch (policy_priority)
  68. {
  69. case POLICY_PRIORITY_FALLBACK:
  70. priority <<= 1;
  71. /* fall-through */
  72. case POLICY_PRIORITY_ROUTED:
  73. priority <<= 1;
  74. /* fall-through */
  75. case POLICY_PRIORITY_DEFAULT:
  76. priority <<= 1;
  77. /* fall-through */
  78. case POLICY_PRIORITY_PASS:
  79. break;
  80. }
  81. /* calculate priority based on selector size, small size = high prio */
  82. src->to_subnet(src, &net, &mask);
  83. priority -= mask;
  84. proto = src->get_protocol(src);
  85. port = net->get_port(net);
  86. net->destroy(net);
  87. dst->to_subnet(dst, &net, &mask);
  88. priority -= mask;
  89. proto = max(proto, dst->get_protocol(dst));
  90. port = max(port, net->get_port(net));
  91. net->destroy(net);
  92. priority <<= 2; /* make some room for the two flags */
  93. priority += port ? 0 : 2;
  94. priority += proto ? 0 : 1;
  95. return priority;
  96. }
  97. /**
  98. * Create a policy entry
  99. */
  100. static ipsec_policy_entry_t *policy_entry_create(ipsec_policy_t *policy)
  101. {
  102. ipsec_policy_entry_t *this;
  103. INIT(this,
  104. .policy = policy,
  105. .priority = calculate_priority(policy->get_priority(policy),
  106. policy->get_source_ts(policy),
  107. policy->get_destination_ts(policy)),
  108. );
  109. return this;
  110. }
  111. /**
  112. * Destroy a policy entry
  113. */
  114. static void policy_entry_destroy(ipsec_policy_entry_t *this)
  115. {
  116. this->policy->destroy(this->policy);
  117. free(this);
  118. }
  119. METHOD(ipsec_policy_mgr_t, add_policy, status_t,
  120. private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst,
  121. traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
  122. policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
  123. policy_priority_t priority)
  124. {
  125. enumerator_t *enumerator;
  126. ipsec_policy_entry_t *entry, *current;
  127. ipsec_policy_t *policy;
  128. if (type != POLICY_IPSEC || direction == POLICY_FWD)
  129. { /* we ignore these policies as we currently have no use for them */
  130. return SUCCESS;
  131. }
  132. DBG2(DBG_ESP, "adding policy %R === %R %N", src_ts, dst_ts,
  133. policy_dir_names, direction);
  134. policy = ipsec_policy_create(src, dst, src_ts, dst_ts, direction, type, sa,
  135. mark, priority);
  136. entry = policy_entry_create(policy);
  137. this->lock->write_lock(this->lock);
  138. enumerator = this->policies->create_enumerator(this->policies);
  139. while (enumerator->enumerate(enumerator, (void**)&current))
  140. {
  141. if (current->priority >= entry->priority)
  142. {
  143. break;
  144. }
  145. }
  146. this->policies->insert_before(this->policies, enumerator, entry);
  147. enumerator->destroy(enumerator);
  148. this->lock->unlock(this->lock);
  149. return SUCCESS;
  150. }
  151. METHOD(ipsec_policy_mgr_t, del_policy, status_t,
  152. private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst,
  153. traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
  154. policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark,
  155. policy_priority_t policy_priority)
  156. {
  157. enumerator_t *enumerator;
  158. ipsec_policy_entry_t *current, *found = NULL;
  159. uint32_t priority;
  160. if (type != POLICY_IPSEC || direction == POLICY_FWD)
  161. { /* we ignore these policies as we currently have no use for them */
  162. return SUCCESS;
  163. }
  164. DBG2(DBG_ESP, "deleting policy %R === %R %N", src_ts, dst_ts,
  165. policy_dir_names, direction);
  166. priority = calculate_priority(policy_priority, src_ts, dst_ts);
  167. this->lock->write_lock(this->lock);
  168. enumerator = this->policies->create_enumerator(this->policies);
  169. while (enumerator->enumerate(enumerator, (void**)&current))
  170. {
  171. if (current->priority == priority &&
  172. current->policy->match(current->policy, src_ts, dst_ts, direction,
  173. sa->reqid, mark, policy_priority))
  174. {
  175. this->policies->remove_at(this->policies, enumerator);
  176. found = current;
  177. break;
  178. }
  179. }
  180. enumerator->destroy(enumerator);
  181. this->lock->unlock(this->lock);
  182. if (found)
  183. {
  184. policy_entry_destroy(found);
  185. return SUCCESS;
  186. }
  187. return FAILED;
  188. }
  189. METHOD(ipsec_policy_mgr_t, flush_policies, status_t,
  190. private_ipsec_policy_mgr_t *this)
  191. {
  192. ipsec_policy_entry_t *entry;
  193. DBG2(DBG_ESP, "flushing policies");
  194. this->lock->write_lock(this->lock);
  195. while (this->policies->remove_last(this->policies,
  196. (void**)&entry) == SUCCESS)
  197. {
  198. policy_entry_destroy(entry);
  199. }
  200. this->lock->unlock(this->lock);
  201. return SUCCESS;
  202. }
  203. METHOD(ipsec_policy_mgr_t, find_by_packet, ipsec_policy_t*,
  204. private_ipsec_policy_mgr_t *this, ip_packet_t *packet, bool inbound,
  205. uint32_t reqid)
  206. {
  207. enumerator_t *enumerator;
  208. ipsec_policy_entry_t *current;
  209. ipsec_policy_t *found = NULL;
  210. this->lock->read_lock(this->lock);
  211. enumerator = this->policies->create_enumerator(this->policies);
  212. while (enumerator->enumerate(enumerator, (void**)&current))
  213. {
  214. ipsec_policy_t *policy = current->policy;
  215. if ((inbound == (policy->get_direction(policy) == POLICY_IN)) &&
  216. policy->match_packet(policy, packet))
  217. {
  218. if (reqid == 0 || reqid == policy->get_reqid(policy))
  219. {
  220. found = policy->get_ref(policy);
  221. break;
  222. }
  223. }
  224. }
  225. enumerator->destroy(enumerator);
  226. this->lock->unlock(this->lock);
  227. return found;
  228. }
  229. METHOD(ipsec_policy_mgr_t, destroy, void,
  230. private_ipsec_policy_mgr_t *this)
  231. {
  232. flush_policies(this);
  233. this->policies->destroy(this->policies);
  234. this->lock->destroy(this->lock);
  235. free(this);
  236. }
  237. /**
  238. * Described in header.
  239. */
  240. ipsec_policy_mgr_t *ipsec_policy_mgr_create()
  241. {
  242. private_ipsec_policy_mgr_t *this;
  243. INIT(this,
  244. .public = {
  245. .add_policy = _add_policy,
  246. .del_policy = _del_policy,
  247. .flush_policies = _flush_policies,
  248. .find_by_packet = _find_by_packet,
  249. .destroy = _destroy,
  250. },
  251. .policies = linked_list_create(),
  252. .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
  253. );
  254. return &this->public;
  255. }