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

# User Rev Content
1 pcg 1.1 /*
2     device-cygwin.C -- Stub for Cygwin environment
3     Copyright (C) 2003 Marc Lehmann <ocg@goof.com>
4 pcg 1.3 Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>,
5     2002-2003 Guus Sliepen <guus@sliepen.eu.org>
6 pcg 1.1
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 pcg 1.3 // a newer driver is available as part of the openvpn package:
29     // http://openvpn.sf.net/
30 pcg 1.1
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 pcg 1.3 #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 pcg 1.2 const char *
81     tap_device::info ()
82     {
83 pcg 1.3 return _("cygwin cipe/openvpn tap device");
84 pcg 1.2 }
85    
86 pcg 1.1 tap_device::tap_device ()
87     {
88 pcg 1.3 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 pcg 1.1 {
112 pcg 1.3 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 pcg 1.1 }
148 pcg 1.3
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 pcg 1.1 }
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 pcg 1.3 info (), conf.ifname, strerror (errno));
283 pcg 1.1 free (pkt);
284     return 0;
285     }
286    
287     id2mac (THISNODE->id, &((*pkt)[6]));
288    
289     if (pkt->is_arp ())
290     {
291 pcg 1.3 if ((*pkt)[22] == 0x08)
292     id2mac (THISNODE->id, &((*pkt)[22]));
293     if ((*pkt)[32] == 0x08)
294     id2mac (THISNODE->id, &((*pkt)[32]));
295 pcg 1.1 }
296    
297     return pkt;
298     }
299    
300     void
301 pcg 1.3 tap_device::send (tap_packet * pkt)
302 pcg 1.1 {
303 pcg 1.3 (*pkt)[6] = 0x08;
304     (*pkt)[7] = 0x00;
305     (*pkt)[8] = 0x58;
306     (*pkt)[9] = 0x00;
307     (*pkt)[10] = 0x00;
308     (*pkt)[11] = 0x01;
309 pcg 1.1
310     if (pkt->is_arp ())
311     {
312 pcg 1.3 if ((*pkt)[22] == 0xfe && (*pkt)[27] == THISNODE->id)
313     memcpy (&(*pkt)[22], &(*pkt)[6], sizeof (mac));
314 pcg 1.1
315 pcg 1.3 if ((*pkt)[32] == 0xfe && (*pkt)[37] == THISNODE->id)
316     memcpy (&(*pkt)[32], &(*pkt)[6], sizeof (mac));
317 pcg 1.1 }
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 pcg 1.3 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 pcg 1.1 }
429 pcg 1.3 #endif