prototype of irdumm - interactive ruby shell for dumm
[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
29 #include "iface.h"
30
31 typedef struct private_iface_t private_iface_t;
32
33 struct private_iface_t {
34 /** public interface */
35 iface_t public;
36 /** device name in guest (eth0) */
37 char *guestif;
38 /** device name at host (tap0) */
39 char *hostif;
40 /** bridge this interface is attached to */
41 bridge_t *bridge;
42 /** guest this interface is attached to */
43 guest_t *guest;
44 /** mconsole for guest */
45 mconsole_t *mconsole;
46 };
47
48 /**
49 * bring an interface up or down
50 */
51 bool iface_control(char *name, bool up)
52 {
53 int s;
54 bool good = FALSE;
55 struct ifreq ifr;
56
57 memset(&ifr, 0, sizeof(struct ifreq));
58 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
59
60 s = socket(AF_INET, SOCK_DGRAM, 0);
61 if (!s)
62 {
63 return FALSE;
64 }
65 if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)
66 {
67 if (up)
68 {
69 ifr.ifr_flags |= IFF_UP;
70 }
71 else
72 {
73 ifr.ifr_flags &= ~IFF_UP;
74 }
75 if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
76 {
77 good = TRUE;
78 }
79 }
80 close(s);
81 return good;
82 }
83
84 /**
85 * Implementation of iface_t.get_guestif.
86 */
87 static char* get_guestif(private_iface_t *this)
88 {
89 return this->guestif;
90 }
91
92 /**
93 * Implementation of iface_t.get_hostif.
94 */
95 static char* get_hostif(private_iface_t *this)
96 {
97 return this->hostif;
98 }
99
100 /**
101 * Implementation of iface_t.set_bridge.
102 */
103 static void set_bridge(private_iface_t *this, bridge_t *bridge)
104 {
105 this->bridge = bridge;
106 }
107
108 /**
109 * Implementation of iface_t.get_bridge
110 */
111 static bridge_t *get_bridge(private_iface_t *this)
112 {
113 return this->bridge;
114 }
115
116 /**
117 * Implementation of iface_t.get_guest
118 */
119 static guest_t* get_guest(private_iface_t *this)
120 {
121 return this->guest;
122 }
123
124 /**
125 * destroy the tap device
126 */
127 static bool destroy_tap(private_iface_t *this)
128 {
129 struct ifreq ifr;
130 int tap;
131
132 if (!iface_control(this->hostif, FALSE))
133 {
134 DBG1("bringing iface down failed: %m");
135 }
136 memset(&ifr, 0, sizeof(ifr));
137 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
138 strncpy(ifr.ifr_name, this->hostif, sizeof(ifr.ifr_name) - 1);
139
140 tap = open(TAP_DEVICE, O_RDWR);
141 if (tap < 0)
142 {
143 DBG1("unable to open tap device %s: %m", TAP_DEVICE);
144 return FALSE;
145 }
146 if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
147 ioctl(tap, TUNSETPERSIST, 0) < 0)
148 {
149 DBG1("removing %s failed: %m", this->hostif);
150 close(tap);
151 return FALSE;
152 }
153 close(tap);
154 return TRUE;
155 }
156
157 /**
158 * create the tap device
159 */
160 static char* create_tap(private_iface_t *this)
161 {
162 struct ifreq ifr;
163 int tap;
164
165 memset(&ifr, 0, sizeof(ifr));
166 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
167 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s",
168 this->guest->get_name(this->guest), this->guestif);
169
170 tap = open(TAP_DEVICE, O_RDWR);
171 if (tap < 0)
172 {
173 DBG1("unable to open tap device %s: %m", TAP_DEVICE);
174 return NULL;
175 }
176 if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
177 ioctl(tap, TUNSETPERSIST, 1) < 0 ||
178 ioctl(tap, TUNSETOWNER, 0))
179 {
180 DBG1("creating new tap device failed: %m");
181 close(tap);
182 return NULL;
183 }
184 close(tap);
185 return strdup(ifr.ifr_name);
186 }
187
188 /**
189 * Implementation of iface_t.destroy.
190 */
191 static void destroy(private_iface_t *this)
192 {
193 if (this->bridge)
194 {
195 this->bridge->disconnect_iface(this->bridge, &this->public);
196 }
197 this->mconsole->del_iface(this->mconsole, this->guestif);
198 destroy_tap(this);
199 free(this->guestif);
200 free(this->hostif);
201 free(this);
202 }
203
204 /**
205 * create the iface instance
206 */
207 iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole)
208 {
209 private_iface_t *this = malloc_thing(private_iface_t);
210
211 this->public.get_hostif = (char*(*)(iface_t*))get_hostif;
212 this->public.get_guestif = (char*(*)(iface_t*))get_guestif;
213 this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge;
214 this->public.get_bridge = (bridge_t*(*)(iface_t*))get_bridge;
215 this->public.get_guest = (guest_t*(*)(iface_t*))get_guest;
216 this->public.destroy = (void*)destroy;
217
218 this->mconsole = mconsole;
219 this->guestif = strdup(name);
220 this->guest = guest;
221 this->hostif = create_tap(this);
222 this->bridge = NULL;
223 if (this->hostif == NULL)
224 {
225 destroy_tap(this);
226 free(this->guestif);
227 free(this);
228 return NULL;
229 }
230 if (!this->mconsole->add_iface(this->mconsole, this->guestif, this->hostif))
231 {
232 DBG1("creating interface '%s' in guest failed", this->guestif);
233 destroy_tap(this);
234 free(this->guestif);
235 free(this->hostif);
236 free(this);
237 return NULL;
238 }
239 if (!iface_control(this->hostif, TRUE))
240 {
241 DBG1("bringing iface '%s' up failed: %m", this->hostif);
242 }
243 return &this->public;
244 }
245