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