30b20349c8aba48458ebbdf5fc00736550069928
[strongswan.git] / src / libcharon / plugins / unity / unity_provider.c
1 /*
2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "unity_provider.h"
17
18 #include <daemon.h>
19
20 typedef struct private_unity_provider_t private_unity_provider_t;
21
22 /**
23 * Private data of an unity_provider_t object.
24 */
25 struct private_unity_provider_t {
26
27 /**
28 * Public unity_provider_t interface.
29 */
30 unity_provider_t public;
31 };
32
33 /**
34 * Attribute enumerator for traffic selector list
35 */
36 typedef struct {
37 /** Implements enumerator_t */
38 enumerator_t public;
39 /** list of traffic selectors to enumerate */
40 linked_list_t *list;
41 /** currently enumerating attribute data */
42 struct __attribute__((packed)) {
43 u_char net[4];
44 u_char mask[4];
45 /* the Cisco client parses this as protocol, src and dst port, the first
46 * two in network order the last in host order - no other clients seem
47 * to support these fields so we don't use them either */
48 u_char padding[6];
49 } attr;
50 } attribute_enumerator_t;
51
52 METHOD(enumerator_t, attribute_enumerate, bool,
53 attribute_enumerator_t *this, configuration_attribute_type_t *type,
54 chunk_t *attr)
55 {
56 traffic_selector_t *ts;
57 u_int8_t i, mask;
58 host_t *net;
59
60 while (TRUE)
61 {
62 if (this->list->remove_first(this->list, (void**)&ts) != SUCCESS)
63 {
64 return FALSE;
65 }
66 if (ts->to_subnet(ts, &net, &mask))
67 {
68 ts->destroy(ts);
69 break;
70 }
71 ts->destroy(ts);
72 }
73 memcpy(this->attr.net, net->get_address(net).ptr, sizeof(this->attr.net));
74 net->destroy(net);
75
76 memset(this->attr.mask, 0, sizeof(this->attr.mask));
77 for (i = 0; i < sizeof(this->attr.mask); i++)
78 {
79 if (mask < 8)
80 {
81 this->attr.mask[i] = 0xFF << (8 - mask);
82 break;
83 }
84 this->attr.mask[i] = 0xFF;
85 mask -= 8;
86 }
87
88 *type = UNITY_SPLIT_INCLUDE;
89 *attr = chunk_create(this->attr.net, sizeof(this->attr));
90
91 return TRUE;
92 }
93
94 METHOD(enumerator_t, attribute_destroy, void,
95 attribute_enumerator_t *this)
96 {
97 this->list->destroy_offset(this->list, offsetof(traffic_selector_t, destroy));
98 free(this);
99 }
100
101 /**
102 * Check if we should send a configured TS as Split-Include attribute
103 */
104 static bool use_ts(traffic_selector_t *ts)
105 {
106 u_int8_t mask;
107 host_t *net;
108
109 if (ts->get_type(ts) != TS_IPV4_ADDR_RANGE)
110 {
111 return FALSE;
112 }
113 if (ts->is_dynamic(ts))
114 {
115 return FALSE;
116 }
117 if (!ts->to_subnet(ts, &net, &mask))
118 {
119 return FALSE;
120 }
121 net->destroy(net);
122 return mask > 0;
123 }
124
125 METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
126 private_unity_provider_t *this, linked_list_t *pools, identification_t *id,
127 linked_list_t *vips)
128 {
129 attribute_enumerator_t *attr_enum;
130 enumerator_t *enumerator;
131 linked_list_t *list, *current;
132 traffic_selector_t *ts;
133 ike_sa_t *ike_sa;
134 peer_cfg_t *peer_cfg;
135 child_cfg_t *child_cfg;
136
137 ike_sa = charon->bus->get_sa(charon->bus);
138 if (!ike_sa || ike_sa->get_version(ike_sa) != IKEV1 ||
139 !ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY) ||
140 !vips->get_count(vips))
141 {
142 return NULL;
143 }
144
145 list = linked_list_create();
146 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
147 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
148 while (enumerator->enumerate(enumerator, &child_cfg))
149 {
150 current = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
151 while (current->remove_first(current, (void**)&ts) == SUCCESS)
152 {
153 if (use_ts(ts))
154 {
155 list->insert_last(list, ts);
156 }
157 else
158 {
159 ts->destroy(ts);
160 }
161 }
162 current->destroy(current);
163 }
164 enumerator->destroy(enumerator);
165
166 if (list->get_count(list) == 0)
167 {
168 list->destroy(list);
169 return NULL;
170 }
171 DBG1(DBG_CFG, "sending %N: %#R",
172 configuration_attribute_type_names, UNITY_SPLIT_INCLUDE, list);
173
174 INIT(attr_enum,
175 .public = {
176 .enumerate = (void*)_attribute_enumerate,
177 .destroy = _attribute_destroy,
178 },
179 .list = list,
180 );
181
182 return &attr_enum->public;
183 }
184
185 METHOD(unity_provider_t, destroy, void,
186 private_unity_provider_t *this)
187 {
188 free(this);
189 }
190
191 /**
192 * See header
193 */
194 unity_provider_t *unity_provider_create()
195 {
196 private_unity_provider_t *this;
197
198 INIT(this,
199 .public = {
200 .provider = {
201 .acquire_address = (void*)return_null,
202 .release_address = (void*)return_false,
203 .create_attribute_enumerator = _create_attribute_enumerator,
204 },
205 .destroy = _destroy,
206 },
207 );
208
209 return &this->public;
210 }