29dbbbfd05e9565785b73592469bb0e49d8fc9f3
[strongswan.git] / src / libcharon / plugins / android / android_handler.c
1 /*
2 * Copyright (C) 2010-2011 Tobias Brunner
3 * Copyright (C) 2010 Martin Willi
4 * 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 #include "android_handler.h"
18
19 #include <networking/host.h>
20 #include <collections/linked_list.h>
21
22 #include <cutils/properties.h>
23
24 typedef struct private_android_handler_t private_android_handler_t;
25
26 /**
27 * Private data of an android_handler_t object.
28 */
29 struct private_android_handler_t {
30
31 /**
32 * Public android_handler_t interface.
33 */
34 android_handler_t public;
35
36 /**
37 * List of registered DNS servers
38 */
39 linked_list_t *dns;
40
41 /**
42 * Whether the VPN frontend is used
43 */
44 bool frontend;
45 };
46
47 /**
48 * Prefixes to be used when installing DNS servers
49 */
50 #define DNS_PREFIX_DEFAULT "net"
51 #define DNS_PREFIX_FRONTEND "vpn"
52
53 /**
54 * Struct to store a pair of old and installed DNS servers
55 */
56 typedef struct {
57 /** installed dns server */
58 host_t *dns;
59 /** old dns server */
60 host_t *old;
61 } dns_pair_t;
62
63 /**
64 * Destroy a pair of old and installed DNS servers
65 */
66 void destroy_dns_pair(dns_pair_t *this)
67 {
68 DESTROY_IF(this->dns);
69 DESTROY_IF(this->old);
70 free(this);
71 }
72
73 /**
74 * Filter pairs of DNS servers
75 */
76 bool filter_dns_pair(void *data, dns_pair_t **in, host_t **out)
77 {
78 *out = (*in)->dns;
79 return TRUE;
80 }
81
82 /**
83 * Read DNS server property with a given index
84 */
85 host_t *get_dns_server(private_android_handler_t *this, int index)
86 {
87 host_t *dns = NULL;
88 char key[10], value[PROPERTY_VALUE_MAX],
89 *prefix = this->frontend ? DNS_PREFIX_FRONTEND : DNS_PREFIX_DEFAULT;
90
91 if (snprintf(key, sizeof(key), "%s.dns%d", prefix, index) >= sizeof(key))
92 {
93 return NULL;
94 }
95
96 if (property_get(key, value, NULL) > 0)
97 {
98 dns = host_create_from_string(value, 0);
99 }
100 return dns;
101 }
102
103 /**
104 * Set DNS server property with a given index
105 */
106 bool set_dns_server(private_android_handler_t *this, int index, host_t *dns)
107 {
108 char key[10], value[PROPERTY_VALUE_MAX],
109 *prefix = this->frontend ? DNS_PREFIX_FRONTEND : DNS_PREFIX_DEFAULT;
110
111 if (snprintf(key, sizeof(key), "%s.dns%d", prefix, index) >= sizeof(key))
112 {
113 return FALSE;
114 }
115
116 if (dns)
117 {
118 if (snprintf(value, sizeof(value), "%H", dns) >= sizeof(value))
119 {
120 return FALSE;
121 }
122 }
123 else
124 {
125 value[0] = '\0';
126 }
127
128 if (property_set(key, value) != 0)
129 {
130 return FALSE;
131 }
132 return TRUE;
133 }
134
135 METHOD(attribute_handler_t, handle, bool,
136 private_android_handler_t *this, identification_t *id,
137 configuration_attribute_type_t type, chunk_t data)
138 {
139 switch (type)
140 {
141 case INTERNAL_IP4_DNS:
142 {
143 host_t *dns;
144 dns_pair_t *pair;
145 int index;
146
147 dns = host_create_from_chunk(AF_INET, data, 0);
148 if (dns)
149 {
150 pair = malloc_thing(dns_pair_t);
151 pair->dns = dns;
152 index = this->dns->get_count(this->dns) + 1;
153 pair->old = get_dns_server(this, index);
154 set_dns_server(this, index, dns);
155 this->dns->insert_last(this->dns, pair);
156 return TRUE;
157 }
158 return FALSE;
159 }
160 default:
161 return FALSE;
162 }
163 }
164
165 METHOD(attribute_handler_t, release, void,
166 private_android_handler_t *this, identification_t *server,
167 configuration_attribute_type_t type, chunk_t data)
168 {
169 if (type == INTERNAL_IP4_DNS)
170 {
171 enumerator_t *enumerator;
172 dns_pair_t *pair;
173 int index;
174
175 enumerator = this->dns->create_enumerator(this->dns);
176 for (index = 1; enumerator->enumerate(enumerator, &pair); index++)
177 {
178 if (chunk_equals(pair->dns->get_address(pair->dns), data))
179 {
180 this->dns->remove_at(this->dns, enumerator);
181 set_dns_server(this, index, pair->old);
182 destroy_dns_pair(pair);
183 }
184 }
185 enumerator->destroy(enumerator);
186 }
187 }
188
189 METHOD(enumerator_t, enumerate_dns, bool,
190 enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data)
191 {
192 *type = INTERNAL_IP4_DNS;
193 *data = chunk_empty;
194 /* stop enumeration */
195 this->enumerate = (void*)return_false;
196 return TRUE;
197 }
198
199 METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
200 android_handler_t *this, identification_t *id, linked_list_t *vips)
201 {
202 enumerator_t *enumerator;
203
204 INIT(enumerator,
205 .enumerate = (void*)_enumerate_dns,
206 .destroy = (void*)free,
207 );
208 return enumerator;
209 }
210
211 METHOD(android_handler_t, destroy, void,
212 private_android_handler_t *this)
213 {
214 this->dns->destroy_function(this->dns, (void*)destroy_dns_pair);
215 free(this);
216 }
217
218 /**
219 * See header
220 */
221 android_handler_t *android_handler_create(bool frontend)
222 {
223 private_android_handler_t *this;
224
225 INIT(this,
226 .public = {
227 .handler = {
228 .handle = _handle,
229 .release = _release,
230 .create_attribute_enumerator = _create_attribute_enumerator,
231 },
232 .destroy = _destroy,
233 },
234 .dns = linked_list_create(),
235 .frontend = frontend,
236 );
237
238 return &this->public;
239 }
240