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