the list of addresses on the interface of a guest is not cached anymore, but queried...
[strongswan.git] / src / dumm / iface.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2002 Jeff Dike
5 *
6 * Based on the "tunctl" utility from Jeff Dike.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19 #include <sys/types.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <net/if.h>
24 #include <sys/ioctl.h>
25 #include <linux/if_tun.h>
26
27 #include <debug.h>
28 #include <utils/linked_list.h>
29
30 #include "iface.h"
31
32 typedef struct private_iface_t private_iface_t;
33
34 struct private_iface_t {
35 /** public interface */
36 iface_t public;
37 /** device name in guest (eth0) */
38 char *guestif;
39 /** device name at host (tap0) */
40 char *hostif;
41 /** bridge this interface is attached to */
42 bridge_t *bridge;
43 /** guest this interface is attached to */
44 guest_t *guest;
45 /** mconsole for guest */
46 mconsole_t *mconsole;
47 };
48
49 /**
50 * bring an interface up or down (host side)
51 */
52 bool iface_control(char *name, bool up)
53 {
54 int s;
55 bool good = FALSE;
56 struct ifreq ifr;
57
58 memset(&ifr, 0, sizeof(struct ifreq));
59 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
60
61 s = socket(AF_INET, SOCK_DGRAM, 0);
62 if (!s)
63 {
64 return FALSE;
65 }
66 if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)
67 {
68 if (up)
69 {
70 ifr.ifr_flags |= IFF_UP;
71 }
72 else
73 {
74 ifr.ifr_flags &= ~IFF_UP;
75 }
76 if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
77 {
78 good = TRUE;
79 }
80 }
81 close(s);
82 return good;
83 }
84
85 /**
86 * Implementation of iface_t.get_guestif.
87 */
88 static char* get_guestif(private_iface_t *this)
89 {
90 return this->guestif;
91 }
92
93 /**
94 * Implementation of iface_t.get_hostif.
95 */
96 static char* get_hostif(private_iface_t *this)
97 {
98 return this->hostif;
99 }
100
101 /**
102 * Implementation of iface_t.add_address
103 */
104 static bool add_address(private_iface_t *this, host_t *addr)
105 {
106 return (this->guest->exec(this->guest, NULL, NULL, "ip addr add %H dev %s",
107 addr, this->guestif) == 0);
108 }
109
110 /**
111 * compile a list of the addresses of an interface
112 */
113 static void compile_address_list(linked_list_t *list, char *address)
114 {
115 host_t *host = host_create_from_string(address, 0);
116 if (host)
117 {
118 list->insert_last(list, host);
119 }
120 }
121
122 /**
123 * delete the list of addresses
124 */
125 static void destroy_address_list(linked_list_t *list)
126 {
127 list->destroy_offset(list, offsetof(host_t, destroy));
128 }
129
130 /**
131 * Implementation of iface_t.create_address_enumerator
132 */
133 static enumerator_t* create_address_enumerator(private_iface_t *this)
134 {
135 linked_list_t *addresses = linked_list_create();
136 this->guest->exec_str(this->guest, (void(*)(void*,char*))compile_address_list,
137 TRUE, addresses,
138 "ip addr list dev %s scope global | "
139 "grep '^ \\+\\(inet6\\? \\)' | "
140 "awk -F '( +|/)' '{ print $3 }'", this->guestif);
141 return enumerator_create_cleaner(addresses->create_enumerator(addresses),
142 (void(*)(void*))destroy_address_list, addresses);
143 }
144
145 /**
146 * Implementation of iface_t.delete_address
147 */
148 static bool delete_address(private_iface_t *this, host_t *addr)
149 {
150 return (this->guest->exec(this->guest, NULL, NULL,
151 "ip addr del %H dev %s", addr, this->guestif) == 0);
152 }
153
154 /**
155 * Implementation of iface_t.set_bridge.
156 */
157 static void set_bridge(private_iface_t *this, bridge_t *bridge)
158 {
159 if (this->bridge == NULL && bridge)
160 {
161 this->guest->exec(this->guest, NULL, NULL,
162 "ip link set %s up", this->guestif);
163 }
164 else if (this->bridge && bridge == NULL)
165 {
166 this->guest->exec(this->guest, NULL, NULL,
167 "ip link set %s down", this->guestif);
168 }
169 this->bridge = bridge;
170 }
171
172 /**
173 * Implementation of iface_t.get_bridge
174 */
175 static bridge_t *get_bridge(private_iface_t *this)
176 {
177 return this->bridge;
178 }
179
180 /**
181 * Implementation of iface_t.get_guest
182 */
183 static guest_t* get_guest(private_iface_t *this)
184 {
185 return this->guest;
186 }
187
188 /**
189 * destroy the tap device
190 */
191 static bool destroy_tap(private_iface_t *this)
192 {
193 struct ifreq ifr;
194 int tap;
195
196 if (!iface_control(this->hostif, FALSE))
197 {
198 DBG1("bringing iface down failed: %m");
199 }
200 memset(&ifr, 0, sizeof(ifr));
201 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
202 strncpy(ifr.ifr_name, this->hostif, sizeof(ifr.ifr_name) - 1);
203
204 tap = open(TAP_DEVICE, O_RDWR);
205 if (tap < 0)
206 {
207 DBG1("unable to open tap device %s: %m", TAP_DEVICE);
208 return FALSE;
209 }
210 if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
211 ioctl(tap, TUNSETPERSIST, 0) < 0)
212 {
213 DBG1("removing %s failed: %m", this->hostif);
214 close(tap);
215 return FALSE;
216 }
217 close(tap);
218 return TRUE;
219 }
220
221 /**
222 * create the tap device
223 */
224 static char* create_tap(private_iface_t *this)
225 {
226 struct ifreq ifr;
227 int tap;
228
229 memset(&ifr, 0, sizeof(ifr));
230 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
231 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s",
232 this->guest->get_name(this->guest), this->guestif);
233
234 tap = open(TAP_DEVICE, O_RDWR);
235 if (tap < 0)
236 {
237 DBG1("unable to open tap device %s: %m", TAP_DEVICE);
238 return NULL;
239 }
240 if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
241 ioctl(tap, TUNSETPERSIST, 1) < 0 ||
242 ioctl(tap, TUNSETOWNER, 0))
243 {
244 DBG1("creating new tap device failed: %m");
245 close(tap);
246 return NULL;
247 }
248 close(tap);
249 return strdup(ifr.ifr_name);
250 }
251
252 /**
253 * Implementation of iface_t.destroy.
254 */
255 static void destroy(private_iface_t *this)
256 {
257 if (this->bridge)
258 {
259 this->bridge->disconnect_iface(this->bridge, &this->public);
260 }
261 /* TODO: iface mgmt is not blocking yet, so wait some ticks */
262 usleep(50000);
263 this->mconsole->del_iface(this->mconsole, this->guestif);
264 destroy_tap(this);
265 free(this->guestif);
266 free(this->hostif);
267 free(this);
268 }
269
270 /**
271 * create the iface instance
272 */
273 iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole)
274 {
275 private_iface_t *this = malloc_thing(private_iface_t);
276
277 this->public.get_hostif = (char*(*)(iface_t*))get_hostif;
278 this->public.get_guestif = (char*(*)(iface_t*))get_guestif;
279 this->public.add_address = (bool(*)(iface_t*, host_t *addr))add_address;
280 this->public.create_address_enumerator = (enumerator_t*(*)(iface_t*))create_address_enumerator;
281 this->public.delete_address = (bool(*)(iface_t*, host_t *addr))delete_address;
282 this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge;
283 this->public.get_bridge = (bridge_t*(*)(iface_t*))get_bridge;
284 this->public.get_guest = (guest_t*(*)(iface_t*))get_guest;
285 this->public.destroy = (void*)destroy;
286
287 this->mconsole = mconsole;
288 this->guestif = strdup(name);
289 this->guest = guest;
290 this->hostif = create_tap(this);
291 this->bridge = NULL;
292 if (this->hostif == NULL)
293 {
294 destroy_tap(this);
295 free(this->guestif);
296 free(this);
297 return NULL;
298 }
299 if (!this->mconsole->add_iface(this->mconsole, this->guestif, this->hostif))
300 {
301 DBG1("creating interface '%s' in guest failed", this->guestif);
302 destroy_tap(this);
303 free(this->guestif);
304 free(this->hostif);
305 free(this);
306 return NULL;
307 }
308 if (!iface_control(this->hostif, TRUE))
309 {
310 DBG1("bringing iface '%s' up failed: %m", this->hostif);
311 }
312 return &this->public;
313 }
314