attribute_manager supports attribute_handler's to handle configuration attributes...
[strongswan.git] / src / charon / plugins / resolv_conf / resolv_conf_handler.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 * $Id$
16 */
17
18 #include "resolv_conf_handler.h"
19
20 #include <unistd.h>
21
22 #include <daemon.h>
23 #include <utils/mutex.h>
24
25 typedef struct private_resolv_conf_handler_t private_resolv_conf_handler_t;
26
27 /**
28 * Private data of an resolv_conf_handler_t object.
29 */
30 struct private_resolv_conf_handler_t {
31
32 /**
33 * Public resolv_conf_handler_t interface.
34 */
35 resolv_conf_handler_t public;
36
37 /**
38 * resolv.conf file to use
39 */
40 char *file;
41
42 /**
43 * Mutex to access file exclusively
44 */
45 mutex_t *mutex;
46 };
47
48 /**
49 * Implementation of attribute_handler_t.handle
50 */
51 static bool handle(private_resolv_conf_handler_t *this, ike_sa_t *ike_sa,
52 configuration_attribute_type_t type, chunk_t data)
53 {
54 FILE *in, *out;
55 char buf[1024];
56 host_t *addr;
57 int family;
58 size_t len;
59 bool handled = FALSE;
60
61 switch (type)
62 {
63 case INTERNAL_IP4_DNS:
64 family = AF_INET;
65 break;
66 case INTERNAL_IP6_DNS:
67 family = AF_INET6;
68 break;
69 default:
70 return FALSE;
71 }
72
73 this->mutex->lock(this->mutex);
74
75 in = fopen(this->file, "r");
76 /* allows us to stream from in to out */
77 unlink(this->file);
78 out = fopen(this->file, "w");
79 if (out)
80 {
81 addr = host_create_from_chunk(family, data, 0);
82 fprintf(out, "nameserver %H # by strongSwan, from %D\n",
83 addr, ike_sa->get_other_id(ike_sa));
84 DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
85 addr->destroy(addr);
86 handled = TRUE;
87
88 /* copy rest of the file */
89 if (in)
90 {
91 while ((len = fread(buf, 1, sizeof(buf), in)))
92 {
93 ignore_result(fwrite(buf, 1, len, out));
94 }
95 fclose(in);
96 }
97 fclose(out);
98 }
99
100 if (!handled)
101 {
102 DBG1(DBG_IKE, "adding DNS server failed", this->file);
103 }
104 this->mutex->unlock(this->mutex);
105 return handled;
106 }
107
108 /**
109 * Implementation of attribute_handler_t.release
110 */
111 static void release(private_resolv_conf_handler_t *this, ike_sa_t *ike_sa,
112 configuration_attribute_type_t type, chunk_t data)
113 {
114 FILE *in, *out;
115 char line[1024], matcher[512], *pos;
116 host_t *addr;
117 int family;
118
119 switch (type)
120 {
121 case INTERNAL_IP4_DNS:
122 family = AF_INET;
123 break;
124 case INTERNAL_IP6_DNS:
125 family = AF_INET6;
126 break;
127 default:
128 return;
129 }
130
131 this->mutex->lock(this->mutex);
132
133 in = fopen(this->file, "r");
134 if (in)
135 {
136 /* allows us to stream from in to out */
137 unlink(this->file);
138 out = fopen(this->file, "w");
139 if (out)
140 {
141 addr = host_create_from_chunk(family, data, 0);
142 snprintf(matcher, sizeof(matcher),
143 "nameserver %H # by strongSwan, from %D\n",
144 addr, ike_sa->get_other_id(ike_sa));
145
146 /* copy all, but matching line */
147 while ((pos = fgets(line, sizeof(line), in)))
148 {
149 if (strneq(line, matcher, strlen(matcher)))
150 {
151 DBG1(DBG_IKE, "removing DNS server %H from %s",
152 addr, this->file);
153 }
154 else
155 {
156 fputs(line, out);
157 }
158 }
159 addr->destroy(addr);
160 fclose(out);
161 }
162 fclose(in);
163 }
164
165 this->mutex->unlock(this->mutex);
166 }
167
168 /**
169 * Implementation of resolv_conf_handler_t.destroy.
170 */
171 static void destroy(private_resolv_conf_handler_t *this)
172 {
173 this->mutex->destroy(this->mutex);
174 free(this);
175 }
176
177 /**
178 * See header
179 */
180 resolv_conf_handler_t *resolv_conf_handler_create()
181 {
182 private_resolv_conf_handler_t *this = malloc_thing(private_resolv_conf_handler_t);
183
184 this->public.handler.handle = (bool(*)(attribute_handler_t*, ike_sa_t*, configuration_attribute_type_t, chunk_t))handle;
185 this->public.handler.release = (void(*)(attribute_handler_t*, ike_sa_t*, configuration_attribute_type_t, chunk_t))release;
186 this->public.destroy = (void(*)(resolv_conf_handler_t*))destroy;
187
188 this->mutex = mutex_create(MUTEX_DEFAULT);
189 this->file = lib->settings->get_str(lib->settings,
190 "charon.plugins.resolv-conf.file", RESOLV_CONF);
191
192 return &this->public;
193 }
194