Add a stroke attribute_handler requesting DNS servers given with leftdns
[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 <utils/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, host_t *vip)
98 {
99 ike_sa_t *ike_sa;
100 peer_cfg_t *peer_cfg;
101 enumerator_t *enumerator;
102 attributes_t *attr;
103
104 ike_sa = charon->bus->get_sa(charon->bus);
105 if (ike_sa)
106 {
107 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
108 this->lock->read_lock(this->lock);
109 enumerator = this->attrs->create_enumerator(this->attrs);
110 while (enumerator->enumerate(enumerator, &attr))
111 {
112 if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
113 {
114 enumerator->destroy(enumerator);
115 return enumerator_create_filter(
116 attr->dns->create_enumerator(attr->dns),
117 (void*)attr_filter, this->lock,
118 (void*)this->lock->unlock);
119 }
120 }
121 enumerator->destroy(enumerator);
122 this->lock->unlock(this->lock);
123 }
124 return enumerator_create_empty();
125 }
126
127 METHOD(stroke_handler_t, add_attributes, void,
128 private_stroke_handler_t *this, stroke_msg_t *msg)
129 {
130 if (msg->add_conn.me.dns)
131 {
132 enumerator_t *enumerator;
133 attributes_t *attr = NULL;
134 host_t *host;
135 char *token;
136
137 enumerator = enumerator_create_token(msg->add_conn.me.dns, ",", " ");
138 while (enumerator->enumerate(enumerator, &token))
139 {
140 if (streq(token, "%config") || streq(token, "%config4"))
141 {
142 host = host_create_any(AF_INET);
143 }
144 else if (streq(token, "%config6"))
145 {
146 host = host_create_any(AF_INET6);
147 }
148 else
149 {
150 host = host_create_from_string(token, 0);
151 }
152 if (host)
153 {
154 if (!attr)
155 {
156 INIT(attr,
157 .name = strdup(msg->add_conn.name),
158 .dns = linked_list_create(),
159 );
160 }
161 attr->dns->insert_last(attr->dns, host);
162 }
163 else
164 {
165 DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
166 }
167 }
168 enumerator->destroy(enumerator);
169 if (attr)
170 {
171 this->lock->write_lock(this->lock);
172 this->attrs->insert_last(this->attrs, attr);
173 this->lock->unlock(this->lock);
174 }
175 }
176 }
177
178 METHOD(stroke_handler_t, del_attributes, void,
179 private_stroke_handler_t *this, stroke_msg_t *msg)
180 {
181 enumerator_t *enumerator;
182 attributes_t *attr;
183
184 this->lock->write_lock(this->lock);
185 enumerator = this->attrs->create_enumerator(this->attrs);
186 while (enumerator->enumerate(enumerator, &attr))
187 {
188 if (streq(msg->del_conn.name, attr->name))
189 {
190 this->attrs->remove_at(this->attrs, enumerator);
191 attributes_destroy(attr);
192 break;
193 }
194 }
195 enumerator->destroy(enumerator);
196 this->lock->unlock(this->lock);
197 }
198
199 METHOD(stroke_handler_t, destroy, void,
200 private_stroke_handler_t *this)
201 {
202 this->lock->destroy(this->lock);
203 this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
204 free(this);
205 }
206
207 /**
208 * See header
209 */
210 stroke_handler_t *stroke_handler_create()
211 {
212 private_stroke_handler_t *this;
213
214 INIT(this,
215 .public = {
216 .handler = {
217 .handle = (void*)return_false,
218 .release = (void*)return_false,
219 .create_attribute_enumerator = _create_attribute_enumerator,
220 },
221 .add_attributes = _add_attributes,
222 .del_attributes = _del_attributes,
223 .destroy = _destroy,
224 },
225 .attrs = linked_list_create(),
226 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
227 );
228
229 return &this->public;
230 }