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