20a71f4c016dd8d802cca06422aa044086f46382
[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 /** list of interface addresses */
48 linked_list_t *addresses;
49 };
50
51 /**
52 * bring an interface up or down (host side)
53 */
54 bool iface_control(char *name, bool up)
55 {
56 int s;
57 bool good = FALSE;
58 struct ifreq ifr;
59
60 memset(&ifr, 0, sizeof(struct ifreq));
61 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
62
63 s = socket(AF_INET, SOCK_DGRAM, 0);
64 if (!s)
65 {
66 return FALSE;
67 }
68 if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)
69 {
70 if (up)
71 {
72 ifr.ifr_flags |= IFF_UP;
73 }
74 else
75 {
76 ifr.ifr_flags &= ~IFF_UP;
77 }
78 if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
79 {
80 good = TRUE;
81 }
82 }
83 close(s);
84 return good;
85 }
86
87 /**
88 * Implementation of iface_t.get_guestif.
89 */
90 static char* get_guestif(private_iface_t *this)
91 {
92 return this->guestif;
93 }
94
95 /**
96 * Implementation of iface_t.get_hostif.
97 */
98 static char* get_hostif(private_iface_t *this)
99 {
100 return this->hostif;
101 }
102
103 /**
104 * Implementation of iface_t.add_address
105 */
106 static bool add_address(private_iface_t *this, host_t *addr)
107 {
108 if (this->guest->exec(this->guest, NULL, NULL, "ip addr add %H dev %s",
109 addr, this->guestif) == 0)
110 {
111 this->addresses->insert_last(this->addresses, addr);
112 return TRUE;
113 }
114 addr->destroy(addr);
115 return FALSE;
116 }
117
118 /**
119 * Implementation of iface_t.create_address_enumerator
120 */
121 static enumerator_t* create_address_enumerator(private_iface_t *this)
122 {
123 return this->addresses->create_enumerator(this->addresses);
124 }
125
126 /**
127 * Implementation of iface_t.delete_address
128 */
129 static bool delete_address(private_iface_t *this, host_t *addr)
130 {
131 enumerator_t *enumerator;
132 bool success = FALSE;
133 host_t *current;
134
135 enumerator = create_address_enumerator(this);
136 while (enumerator->enumerate(enumerator, &current))
137 {
138 if (current->ip_equals(current, addr))
139 {
140 if (this->guest->exec(this->guest, NULL, NULL,
141 "ip addr del %H dev %s", current, this->guestif) == 0)
142 {
143 this->addresses->remove_at(this->addresses, enumerator);
144 success = TRUE;
145 }
146 break;
147 }
148 }
149 enumerator->destroy(enumerator);
150 return success;
151 }
152
153 /**
154 * Implementation of iface_t.set_bridge.
155 */
156 static void set_bridge(private_iface_t *this, bridge_t *bridge)
157 {
158 if (this->bridge == NULL && bridge)
159 {
160 this->guest->exec(this->guest, NULL, NULL,
161 "ip link set %s up", this->guestif);
162 }
163 else if (this->bridge && bridge == NULL)
164 {
165 this->guest->exec(this->guest, NULL, NULL,
166 "ip link set %s down", this->guestif);
167 }
168 this->bridge = bridge;
169 }
170
171 /**
172 * Implementation of iface_t.get_bridge
173 */
174 static bridge_t *get_bridge(private_iface_t *this)
175 {
176 return this->bridge;
177 }
178
179 /**
180 * Implementation of iface_t.get_guest
181 */
182 static guest_t* get_guest(private_iface_t *this)
183 {
184 return this->guest;
185 }
186
187 /**
188 * destroy the tap device
189 */
190 static bool destroy_tap(private_iface_t *this)
191 {
192 struct ifreq ifr;
193 int tap;
194
195 if (!iface_control(this->hostif, FALSE))
196 {
197 DBG1("bringing iface down failed: %m");
198 }
199 memset(&ifr, 0, sizeof(ifr));
200 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
201 strncpy(ifr.ifr_name, this->hostif, sizeof(ifr.ifr_name) - 1);
202
203 tap = open(TAP_DEVICE, O_RDWR);
204 if (tap < 0)
205 {
206 DBG1("unable to open tap device %s: %m", TAP_DEVICE);
207 return FALSE;
208 }
209 if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
210 ioctl(tap, TUNSETPERSIST, 0) < 0)
211 {
212 DBG1("removing %s failed: %m", this->hostif);
213 close(tap);
214 return FALSE;
215 }
216 close(tap);
217 return TRUE;
218 }
219
220 /**
221 * create the tap device
222 */
223 static char* create_tap(private_iface_t *this)
224 {
225 struct ifreq ifr;
226 int tap;
227
228 memset(&ifr, 0, sizeof(ifr));
229 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
230 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s",
231 this->guest->get_name(this->guest), this->guestif);
232
233 tap = open(TAP_DEVICE, O_RDWR);
234 if (tap < 0)
235 {
236 DBG1("unable to open tap device %s: %m", TAP_DEVICE);
237 return NULL;
238 }
239 if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
240 ioctl(tap, TUNSETPERSIST, 1) < 0 ||
241 ioctl(tap, TUNSETOWNER, 0))
242 {
243 DBG1("creating new tap device failed: %m");
244 close(tap);
245 return NULL;
246 }
247 close(tap);
248 return strdup(ifr.ifr_name);
249 }
250
251 /**
252 * Implementation of iface_t.destroy.
253 */
254 static void destroy(private_iface_t *this)
255 {
256 if (this->bridge)
257 {
258 this->bridge->disconnect_iface(this->bridge, &this->public);
259 }
260 /* TODO: iface mgmt is not blocking yet, so wait some ticks */
261 usleep(50000);
262 this->mconsole->del_iface(this->mconsole, this->guestif);
263 destroy_tap(this);
264 free(this->guestif);
265 free(this->hostif);
266 this->addresses->destroy(this->addresses);
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 this->addresses = linked_list_create();
313 return &this->public;
314 }
315