Moved data structures to new collections subfolder
[strongswan.git] / src / libcharon / plugins / stroke / stroke_handler.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 "stroke_handler.h"
17
18 #include <daemon.h>
19 #include <collections/linked_list.h>
20 #include <threading/rwlock.h>
21
22 typedef struct private_stroke_handler_t private_stroke_handler_t;
23
24 /**
25 * Private data of an stroke_handler_t object.
26 */
27 struct private_stroke_handler_t {
28
29 /**
30 * Public stroke_handler_t interface.
31 */
32 stroke_handler_t public;
33
34 /**
35 * List of connection specific attributes, as attributes_t
36 */
37 linked_list_t *attrs;
38
39 /**
40 * rwlock to lock access to pools
41 */
42 rwlock_t *lock;
43 };
44
45 /**
46 * Attributes assigned to a connection
47 */
48 typedef struct {
49 /** name of the connection */
50 char *name;
51 /** list of DNS attributes, as host_t */
52 linked_list_t *dns;
53 } attributes_t;
54
55 /**
56 * Destroy an attributes_t entry
57 */
58 static void attributes_destroy(attributes_t *this)
59 {
60 this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
61 free(this->name);
62 free(this);
63 }
64
65 /**
66 * Filter function to convert host to DNS configuration attributes
67 */
68 static bool attr_filter(void *lock, host_t **in,
69 configuration_attribute_type_t *type,
70 void *dummy, chunk_t *data)
71 {
72 host_t *host = *in;
73
74 switch (host->get_family(host))
75 {
76 case AF_INET:
77 *type = INTERNAL_IP4_DNS;
78 break;
79 case AF_INET6:
80 *type = INTERNAL_IP6_DNS;
81 break;
82 default:
83 return FALSE;
84 }
85 if (host->is_anyaddr(host))
86 {
87 *data = chunk_empty;
88 }
89 else
90 {
91 *data = host->get_address(host);
92 }
93 return TRUE;
94 }
95
96 METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
97 private_stroke_handler_t *this, identification_t *server,
98 linked_list_t *vips)
99 {
100 ike_sa_t *ike_sa;
101 peer_cfg_t *peer_cfg;
102 enumerator_t *enumerator;
103 attributes_t *attr;
104
105 ike_sa = charon->bus->get_sa(charon->bus);
106 if (ike_sa)
107 {
108 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
109 this->lock->read_lock(this->lock);
110 enumerator = this->attrs->create_enumerator(this->attrs);
111 while (enumerator->enumerate(enumerator, &attr))
112 {
113 if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
114 {
115 enumerator->destroy(enumerator);
116 return enumerator_create_filter(
117 attr->dns->create_enumerator(attr->dns),
118 (void*)attr_filter, this->lock,
119 (void*)this->lock->unlock);
120 }
121 }
122 enumerator->destroy(enumerator);
123 this->lock->unlock(this->lock);
124 }
125 return enumerator_create_empty();
126 }
127
128 METHOD(stroke_handler_t, add_attributes, void,
129 private_stroke_handler_t *this, stroke_msg_t *msg)
130 {
131 if (msg->add_conn.me.dns)
132 {
133 enumerator_t *enumerator;
134 attributes_t *attr = NULL;
135 host_t *host;
136 char *token;
137
138 enumerator = enumerator_create_token(msg->add_conn.me.dns, ",", " ");
139 while (enumerator->enumerate(enumerator, &token))
140 {
141 if (streq(token, "%config") || streq(token, "%config4"))
142 {
143 host = host_create_any(AF_INET);
144 }
145 else if (streq(token, "%config6"))
146 {
147 host = host_create_any(AF_INET6);
148 }
149 else
150 {
151 host = host_create_from_string(token, 0);
152 }
153 if (host)
154 {
155 if (!attr)
156 {
157 INIT(attr,
158 .name = strdup(msg->add_conn.name),
159 .dns = linked_list_create(),
160 );
161 }
162 attr->dns->insert_last(attr->dns, host);
163 }
164 else
165 {
166 DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
167 }
168 }
169 enumerator->destroy(enumerator);
170 if (attr)
171 {
172 this->lock->write_lock(this->lock);
173 this->attrs->insert_last(this->attrs, attr);
174 this->lock->unlock(this->lock);
175 }
176 }
177 }
178
179 METHOD(stroke_handler_t, del_attributes, void,
180 private_stroke_handler_t *this, stroke_msg_t *msg)
181 {
182 enumerator_t *enumerator;
183 attributes_t *attr;
184
185 this->lock->write_lock(this->lock);
186 enumerator = this->attrs->create_enumerator(this->attrs);
187 while (enumerator->enumerate(enumerator, &attr))
188 {
189 if (streq(msg->del_conn.name, attr->name))
190 {
191 this->attrs->remove_at(this->attrs, enumerator);
192 attributes_destroy(attr);
193 break;
194 }
195 }
196 enumerator->destroy(enumerator);
197 this->lock->unlock(this->lock);
198 }
199
200 METHOD(stroke_handler_t, destroy, void,
201 private_stroke_handler_t *this)
202 {
203 this->lock->destroy(this->lock);
204 this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
205 free(this);
206 }
207
208 /**
209 * See header
210 */
211 stroke_handler_t *stroke_handler_create()
212 {
213 private_stroke_handler_t *this;
214
215 INIT(this,
216 .public = {
217 .handler = {
218 .handle = (void*)return_false,
219 .release = (void*)return_false,
220 .create_attribute_enumerator = _create_attribute_enumerator,
221 },
222 .add_attributes = _add_attributes,
223 .del_attributes = _del_attributes,
224 .destroy = _destroy,
225 },
226 .attrs = linked_list_create(),
227 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
228 );
229
230 return &this->public;
231 }