ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/tincd/bsd/device.c
Revision: 1.1
Committed: Fri Mar 25 16:05:22 2005 UTC (19 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_9, rel-2_01, rel-3_0, rel-2_2, rel-2_0, rel-2_21, rel-2_22, rel-2_25, HEAD
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 device.c -- Interaction BSD tun/tap device
3 Copyright (C) 2001-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
4 2001-2004 Guus Sliepen <guus@tinc-vpn.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 $Id: device.c 1398 2004-11-01 15:18:53Z guus $
21 */
22
23 #define DEFAULT_DEVICE "/dev/tun0"
24
25 typedef enum device_type {
26 DEVICE_TYPE_TUN,
27 DEVICE_TYPE_TUNIFHEAD,
28 DEVICE_TYPE_TAP,
29 } device_type_t;
30
31 int device_fd = -1;
32 char *device;
33 char *iface;
34 char *device_info;
35 static int device_total_in = 0;
36 static int device_total_out = 0;
37 #ifdef HAVE_OPENBSD
38 static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
39 #else
40 static device_type_t device_type = DEVICE_TYPE_TUN;
41 #endif
42
43 bool setup_device(void) {
44 char *type;
45
46 cp();
47
48 if(!get_config_string(lookup_config(config_tree, "Device"), &device))
49 device = DEFAULT_DEVICE;
50
51 if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
52 iface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
53
54 if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
55 logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
56 return false;
57 }
58
59 if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
60 if(!strcasecmp(type, "tun"))
61 /* use default */;
62 else if(!strcasecmp(type, "tunnohead"))
63 device_type = DEVICE_TYPE_TUN;
64 else if(!strcasecmp(type, "tunifhead"))
65 device_type = DEVICE_TYPE_TUNIFHEAD;
66 else if(!strcasecmp(type, "tap"))
67 device_type = DEVICE_TYPE_TAP;
68 else {
69 logger(LOG_ERR, _("Unknown device type %s!"), type);
70 return false;
71 }
72 } else {
73 if(strstr(device, "tap"))
74 device_type = DEVICE_TYPE_TAP;
75 }
76
77 switch(device_type) {
78 default:
79 device_type = DEVICE_TYPE_TUN;
80 case DEVICE_TYPE_TUN:
81 #ifdef TUNSIFHEAD
82 {
83 const int zero = 0;
84 if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
85 logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
86 return false;
87 }
88 }
89 #endif
90 #if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST)
91 {
92 const int mode = IFF_BROADCAST | IFF_MULTICAST;
93 ioctl(device_fd, TUNSIFMODE, &mode, sizeof mode);
94 }
95 #endif
96
97 device_info = _("Generic BSD tun device");
98 break;
99 case DEVICE_TYPE_TUNIFHEAD:
100 #ifdef TUNSIFHEAD
101 {
102 const int one = 1;
103 if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
104 logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
105 return false;
106 }
107 }
108 #endif
109 #if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST)
110 {
111 const int mode = IFF_BROADCAST | IFF_MULTICAST;
112 ioctl(device_fd, TUNSIFMODE, &mode, sizeof mode);
113 }
114 #endif
115
116 device_info = _("Generic BSD tun device");
117 break;
118 case DEVICE_TYPE_TAP:
119 if(routing_mode == RMODE_ROUTER)
120 overwrite_mac = true;
121 device_info = _("Generic BSD tap device");
122 break;
123 }
124
125 logger(LOG_INFO, _("%s is a %s"), device, device_info);
126
127 return true;
128 }
129
130 void close_device(void) {
131 cp();
132
133 close(device_fd);
134 }
135
136 bool read_packet(vpn_packet_t *packet) {
137 int lenin;
138
139 cp();
140
141 switch(device_type) {
142 case DEVICE_TYPE_TUN:
143 if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
144 logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
145 device, strerror(errno));
146 return false;
147 }
148
149 switch(packet->data[14] >> 4) {
150 case 4:
151 packet->data[12] = 0x08;
152 packet->data[13] = 0x00;
153 break;
154 case 6:
155 packet->data[12] = 0x86;
156 packet->data[13] = 0xDD;
157 break;
158 default:
159 ifdebug(TRAFFIC) logger(LOG_ERR,
160 _ ("Unknown IP version %d while reading packet from %s %s"),
161 packet->data[14] >> 4, device_info, device);
162 return false;
163 }
164
165 packet->len = lenin + 14;
166 break;
167
168 case DEVICE_TYPE_TUNIFHEAD: {
169 u_int32_t type;
170 struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}};
171
172 if((lenin = readv(device_fd, vector, 2)) <= 0) {
173 logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
174 device, strerror(errno));
175 return false;
176 }
177
178 switch (ntohl(type)) {
179 case AF_INET:
180 packet->data[12] = 0x08;
181 packet->data[13] = 0x00;
182 break;
183
184 case AF_INET6:
185 packet->data[12] = 0x86;
186 packet->data[13] = 0xDD;
187 break;
188
189 default:
190 ifdebug(TRAFFIC) logger(LOG_ERR,
191 _ ("Unknown address family %x while reading packet from %s %s"),
192 ntohl(type), device_info, device);
193 return false;
194 }
195
196 packet->len = lenin + 10;
197 break;
198 }
199
200 case DEVICE_TYPE_TAP:
201 if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
202 logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
203 device, strerror(errno));
204 return false;
205 }
206
207 packet->len = lenin;
208 break;
209
210 default:
211 return false;
212 }
213
214 device_total_in += packet->len;
215
216 ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"),
217 packet->len, device_info);
218
219 return true;
220 }
221
222 bool write_packet(vpn_packet_t *packet)
223 {
224 cp();
225
226 ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
227 packet->len, device_info);
228
229 switch(device_type) {
230 case DEVICE_TYPE_TUN:
231 if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
232 logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
233 device, strerror(errno));
234 return false;
235 }
236 break;
237
238 case DEVICE_TYPE_TUNIFHEAD: {
239 u_int32_t type;
240 struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}};
241 int af;
242
243 af = (packet->data[12] << 8) + packet->data[13];
244
245 switch (af) {
246 case 0x0800:
247 type = htonl(AF_INET);
248 break;
249 case 0x86DD:
250 type = htonl(AF_INET6);
251 break;
252 default:
253 ifdebug(TRAFFIC) logger(LOG_ERR,
254 _("Unknown address family %x while writing packet to %s %s"),
255 af, device_info, device);
256 return false;
257 }
258
259 if(writev(device_fd, vector, 2) < 0) {
260 logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
261 strerror(errno));
262 return false;
263 }
264 break;
265 }
266
267 case DEVICE_TYPE_TAP:
268 if(write(device_fd, packet->data, packet->len) < 0) {
269 logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
270 device, strerror(errno));
271 return false;
272 }
273 break;
274
275 default:
276 return false;
277 }
278
279 device_total_out += packet->len;
280
281 return true;
282 }
283
284 void dump_device_stats(void)
285 {
286 cp();
287
288 logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
289 logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
290 logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
291 }