ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/device-cygwin.C
Revision: 1.3
Committed: Wed Oct 15 00:25:15 2003 UTC (20 years, 7 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.2: +339 -15 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 device-cygwin.C -- Stub for Cygwin environment
3 Copyright (C) 2003 Marc Lehmann <ocg@goof.com>
4 Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>,
5 2002-2003 Guus Sliepen <guus@sliepen.eu.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 // unfortunately, there is be no way to set MAC addresses under windows,
23 // and the default cipedrvr uses a different MAC address than we do,
24 // so this module tries to fix mac addresses in packets and arp packets.
25 // this is probably not very fast, but neither is cygwin nor poll.
26 //
27 // http://cipe-win32.sourceforge.net/
28 // a newer driver is available as part of the openvpn package:
29 // http://openvpn.sf.net/
30
31 #include "config.h"
32
33 #include <stdio.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <syslog.h>
40 #include <cstring>
41
42 #include "conf.h"
43 #include "util.h"
44
45 #include <w32api/windows.h>
46 #include <w32api/winioctl.h>
47
48 #define REG_CONTROL_NET "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
49
50 #define USERMODEDEVICEDIR "\\\\.\\"
51 #define USERDEVICEDIR "\\??\\"
52 #define TAPSUFFIX ".tap"
53
54 #define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
55
56 #define TAP_IOCTL_GET_LASTMAC TAP_CONTROL_CODE(0, METHOD_BUFFERED)
57 #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
58 #define TAP_IOCTL_SET_STATISTICS TAP_CONTROL_CODE(2, METHOD_BUFFERED)
59
60 static HANDLE device_handle = INVALID_HANDLE_VALUE;
61
62 static const char *
63 wstrerror (int err)
64 {
65 static char buf[1024];
66
67 if (!FormatMessage
68 (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
69 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof (buf), NULL))
70 {
71 strncpy (buf, _("(unable to format errormessage)"), sizeof (buf));
72 };
73
74 if ((char *newline = strchr (buf, '\r')))
75 *newline = '\0';
76
77 return buf;
78 }
79
80 const char *
81 tap_device::info ()
82 {
83 return _("cygwin cipe/openvpn tap device");
84 }
85
86 tap_device::tap_device ()
87 {
88 HKEY key, key2;
89 int i;
90
91 char regpath[1024];
92 char adapterid[1024];
93 char adaptername[1024];
94 char tapname[1024];
95 long len;
96
97 bool found = false;
98
99 int sock, err;
100
101 /* Open registry and look for network adapters */
102
103 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_CONTROL_NET, 0, KEY_READ, &key))
104 {
105 slog (L_ERR, _("Unable to read registry: %s"),
106 wstrerror (GetLastError ()));
107 return false;
108 }
109
110 for (i = 0;; i++)
111 {
112 len = sizeof (adapterid);
113 if (RegEnumKeyEx (key, i, adapterid, &len, 0, 0, 0, NULL))
114 break;
115
116 /* Find out more about this adapter */
117
118 snprintf (regpath, sizeof (regpath), "%s\\%s\\Connection",
119 REG_CONTROL_NET, adapterid);
120
121 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
122 continue;
123
124 len = sizeof (adaptername);
125 err = RegQueryValueEx (key2, "Name", 0, 0, adaptername, &len);
126
127 RegCloseKey (key2);
128
129 if (err)
130 continue;
131
132 if (strcmp (conf.ifname, adapterid))
133 continue;
134
135 found = true;
136 break;
137
138 snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX,
139 adapterid);
140 device_handle = CreateFile (tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, indent: Standard input: 237: Error:Stmt nesting error.FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
141 0);
142 if (device_handle != INVALID_HANDLE_VALUE)
143 {
144 found = true;
145 break;
146 }
147 }
148
149 RegCloseKey (key);
150
151 if (!found)
152 {
153 slog (L_ERR, _("No Windows tap device found!"));
154 return false;
155 }
156
157 if (!device)
158 device = xstrdup (adapterid);
159
160 if (!iface)
161 iface = xstrdup (adaptername);
162
163 /* Try to open the corresponding tap device */
164
165 if (device_handle == INVALID_HANDLE_VALUE)
166 {
167 snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX,
168 device);
169 device_handle =
170 CreateFile (tapname, GENERIC_WRITE | GENERIC_READ, 0, 0,
171 OPEN_EXISTING,
172 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
173 }
174
175 if (device_handle == INVALID_HANDLE_VALUE)
176 {
177 slog (L_ERR, _("%s (%s) is not a usable Windows tap device: %s"),
178 device, iface, wstrerror (GetLastError ()));
179 return false;
180 }
181
182 /* Get MAC address from tap device */
183
184 if (!DeviceIoControl
185 (device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof (mymac.x), mymac.x,
186 sizeof (mymac.x), &len, 0))
187 {
188 slog (L_ERR,
189 _
190 ("Could not get MAC address from Windows tap device %s (%s): %s"),
191 device, iface, wstrerror (GetLastError ()));
192 return false;
193 }
194
195 if (routing_mode == RMODE_ROUTER)
196 {
197 overwrite_mac = 1;
198 }
199
200 /* Create a listening socket */
201
202 err = getaddrinfo (NULL, myport, &hint, &ai);
203
204 if (err || !ai)
205 {
206 slog (L_ERR, _("System call `%s' failed: %s"), "getaddrinfo",
207 gai_strerror (errno));
208 return false;
209 }
210
211 sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
212
213 if (sock < 0)
214 {
215 slog (L_ERR, _("System call `%s' failed: %s"), "socket",
216 strerror (errno));
217 return false;
218 }
219
220 if (bind (sock, ai->ai_addr, ai->ai_addrlen))
221 {
222 slog (L_ERR, _("System call `%s' failed: %s"), "bind",
223 strerror (errno));
224 return false;
225 }
226
227 freeaddrinfo (ai);
228
229 if (listen (sock, 1))
230 {
231 slog (L_ERR, _("System call `%s' failed: %s"), "listen",
232 strerror (errno));
233 return false;
234 }
235
236 /* Start the tap reader */
237
238 thread = CreateThread (NULL, 0, tapreader, NULL, 0, NULL);
239
240 if (!thread)
241 {
242 slog (L_ERR, _("System call `%s' failed: %s"), "CreateThread",
243 wstrerror (GetLastError ()));
244 return false;
245 }
246
247 /* Wait for the tap reader to connect back to us */
248
249 if ((device_fd = accept (sock, NULL, 0)) == -1)
250 {
251 slog (L_ERR, _("System call `%s' failed: %s"), "accept",
252 strerror (errno));
253 return false;
254 }
255
256 closesocket (sock);
257
258 device_info = _("Windows tap device");
259
260 slog (L_INFO, _("%s (%s) is a %s"), device, iface, device_info);
261
262 return true;
263 }
264
265 }
266
267 tap_device::~tap_device ()
268 {
269 close (fd);
270 }
271
272 tap_packet *
273 tap_device::recv ()
274 {
275 tap_packet *pkt = new tap_packet;
276
277 pkt->len = read (fd, &((*pkt)[0]), MAX_MTU);
278
279 if (pkt->len <= 0)
280 {
281 slog (L_ERR, _("error while reading from %s %s: %s"),
282 info (), conf.ifname, strerror (errno));
283 free (pkt);
284 return 0;
285 }
286
287 id2mac (THISNODE->id, &((*pkt)[6]));
288
289 if (pkt->is_arp ())
290 {
291 if ((*pkt)[22] == 0x08)
292 id2mac (THISNODE->id, &((*pkt)[22]));
293 if ((*pkt)[32] == 0x08)
294 id2mac (THISNODE->id, &((*pkt)[32]));
295 }
296
297 return pkt;
298 }
299
300 void
301 tap_device::send (tap_packet * pkt)
302 {
303 (*pkt)[6] = 0x08;
304 (*pkt)[7] = 0x00;
305 (*pkt)[8] = 0x58;
306 (*pkt)[9] = 0x00;
307 (*pkt)[10] = 0x00;
308 (*pkt)[11] = 0x01;
309
310 if (pkt->is_arp ())
311 {
312 if ((*pkt)[22] == 0xfe && (*pkt)[27] == THISNODE->id)
313 memcpy (&(*pkt)[22], &(*pkt)[6], sizeof (mac));
314
315 if ((*pkt)[32] == 0xfe && (*pkt)[37] == THISNODE->id)
316 memcpy (&(*pkt)[32], &(*pkt)[6], sizeof (mac));
317 }
318
319 if (write (fd, &((*pkt)[0]), pkt->len) < 0)
320 slog (L_ERR, _("can't write to %s %s: %s"), info (), conf.ifname,
321 strerror (errno));
322 }
323
324 #if 0
325
326 slog (L_DEBUG, _indent: Standard input:377: Error:Stmt nesting error.
327 ("Tap reader running"));
328
329 /* Read from tap device and send to parent */
330
331 overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
332
333 for indent
334 : Standard input: 320: Error:Stmt nesting error.(;;
335 )
336 {
337 overlapped.Offset = 0;
338 overlapped.OffsetHigh = 0;
339 ResetEvent (overlapped.hEvent);
340
341 status = ReadFile (device_handle, buf, sizeof (buf), &len, &overlapped);
342
343 if (!status)
344 {
345 if (GetLastError () == ERROR_IO_PENDING)
346 {
347 WaitForSingleObject (overlapped.hEvent, INFINITE);
348 if (!GetOverlappedResult (device_handle, &overlapped, &len, FALSE))
349 continue;
350 }
351 else
352 {
353 slog (L_ERR, _("Error while reading from %s %s: %s"),
354 device_info, device, strerror (errno));
355 return -1;
356 }
357 }
358
359 if (send (sock, buf, len, 0) <= 0)
360 return -1;
361 }
362 }
363
364 void
365 close_device (void)
366 {
367 cp ();
368
369 CloseHandle (device_handle);
370 }
371
372 bool
373 read_packet (vpn_packet_t * packet)
374 {
375 int lenin;
376
377 cp ();
378
379 if ((lenin = recv (device_fd, packet->data, MTU, 0)) <= 0)
380 {
381 slog (L_ERR, _("Error while reading from %s %s: %s"), device_info,
382 device, strerror (errno));
383 return false;
384 }
385
386 packet->len = lenin;
387
388 device_total_in += packet->len;
389
390 ifdebug (TRAFFIC) slog (L_DEBUG, _("Read packet of %d bytes from %s"),
391 packet->len, device_info);
392
393 return true;
394 }
395
396 bool
397 write_packet (vpn_packet_t * packet)
398 {
399 long lenout;
400 OVERLAPPED overlapped = { 0 };
401
402 cp ();
403
404 ifdebug (TRAFFIC) slog (L_DEBUG, _("Writing packet of %d bytes to %s"),
405 packet->len, device_info);
406
407 if (!WriteFile
408 (device_handle, packet->data, packet->len, &lenout, &overlapped))
409 {
410 slog (L_ERR, _("Error while writing to %s %s: %s"), device_info,
411 device, wstrerror (GetLastError ()));
412 return false;
413 }
414
415 device_total_out += packet->len;
416
417 return true;
418 }
419
420 void
421 dump_device_stats (void)
422 {
423 cp ();
424
425 slog (L_DEBUG, _("Statistics for %s %s:"), device_info, device);
426 slog (L_DEBUG, _(" total bytes in: %10d"), device_total_in);
427 slog (L_DEBUG, _(" total bytes out: %10d"), device_total_out);
428 }
429 #endif