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