ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/device-cygwin.C
Revision: 1.4
Committed: Wed Oct 15 01:35:45 2003 UTC (20 years, 7 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +24 -95 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 static mac my_mac;
62
63 static const char *
64 wstrerror (int err)
65 {
66 static char buf[1024];
67
68 if (!FormatMessage
69 (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
70 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof (buf), NULL))
71 {
72 strncpy (buf, _("(unable to format errormessage)"), sizeof (buf));
73 };
74
75 if ((char *newline = strchr (buf, '\r')))
76 *newline = '\0';
77
78 return buf;
79 }
80
81 const char *
82 tap_device::info ()
83 {
84 return _("cygwin cipe/openvpn tap device");
85 }
86
87 tap_device::tap_device ()
88 {
89 HKEY key, key2;
90 int i;
91
92 char regpath[1024];
93 char adapterid[1024];
94 char adaptername[1024];
95 char tapname[1024];
96 long len;
97
98 bool found = false;
99
100 int sock, err;
101
102 /* Open registry and look for network adapters */
103
104 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_CONTROL_NET, 0, KEY_READ, &key))
105 {
106 slog (L_ERR, _("Unable to read registry: %s"),
107 wstrerror (GetLastError ()));
108 return false;
109 }
110
111 for (i = 0;; i++)
112 {
113 len = sizeof (adapterid);
114 if (RegEnumKeyEx (key, i, adapterid, &len, 0, 0, 0, NULL))
115 break;
116
117 /* Find out more about this adapter */
118
119 snprintf (regpath, sizeof (regpath), "%s\\%s\\Connection",
120 REG_CONTROL_NET, adapterid);
121
122 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
123 continue;
124
125 len = sizeof (adaptername);
126 err = RegQueryValueEx (key2, "Name", 0, 0, adaptername, &len);
127
128 RegCloseKey (key2);
129
130 if (err)
131 continue;
132
133 if (conf.ifname)
134 {
135 if (strcmp (conf.ifname, adapterid))
136 continue;
137 }
138 else
139 {
140 found = true;
141 break;
142 }
143
144 snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
145 device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0,
146 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
147 if (device_handle != INVALID_HANDLE_VALUE)
148 {
149 found = true;
150 break;
151 }
152 }
153
154 RegCloseKey (key);
155
156 if (!found)
157 {
158 slog (L_ERR, _("No Windows tap device found!"));
159 exit (1);
160 }
161
162 strcpy (ifrname, adaptername);
163
164 /* Try to open the corresponding tap device */
165
166 if (device_handle == INVALID_HANDLE_VALUE)
167 {
168 snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, 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 exit (1);
180 }
181
182 fd = cygwin_attach_handle_to_fd (tapname, -1, device_handle, 1, GENERIC_WRITE | GENERIC_READ);
183
184 /* Get MAC address from tap device */
185
186 if (!DeviceIoControl
187 (device_handle, TAP_IOCTL_GET_MAC, &mac, sizeof (mac), &mac, sizeof (mac), &len, 0))
188 {
189 slog (L_ERR,
190 _("Could not get MAC address from Windows tap device %s (%s): %s"),
191 device, iface, wstrerror (GetLastError ()));
192 exit (1);
193 }
194 }
195
196 tap_device::~tap_device ()
197 {
198 close (fd);
199 }
200
201 tap_packet *
202 tap_device::recv ()
203 {
204 tap_packet *pkt = new tap_packet;
205
206 pkt->len = read (fd, &((*pkt)[0]), MAX_MTU);
207
208 if (pkt->len <= 0)
209 {
210 slog (L_ERR, _("error while reading from %s %s: %s"),
211 info (), conf.ifname, strerror (errno));
212 free (pkt);
213 return 0;
214 }
215
216 id2mac (THISNODE->id, &((*pkt)[6]));
217
218 if (pkt->is_arp ())
219 {
220 if ((*pkt)[22] == 0x08)
221 id2mac (THISNODE->id, &((*pkt)[22]));
222 if ((*pkt)[32] == 0x08)
223 id2mac (THISNODE->id, &((*pkt)[32]));
224 }
225
226 return pkt;
227 }
228
229 void
230 tap_device::send (tap_packet * pkt)
231 {
232 (*pkt)[6] = 0x08;
233 (*pkt)[7] = 0x00;
234 (*pkt)[8] = 0x58;
235 (*pkt)[9] = 0x00;
236 (*pkt)[10] = 0x00;
237 (*pkt)[11] = 0x01;
238
239 if (pkt->is_arp ())
240 {
241 if ((*pkt)[22] == 0xfe && (*pkt)[27] == THISNODE->id)
242 memcpy (&(*pkt)[22], &(*pkt)[6], sizeof (mac));
243
244 if ((*pkt)[32] == 0xfe && (*pkt)[37] == THISNODE->id)
245 memcpy (&(*pkt)[32], &(*pkt)[6], sizeof (mac));
246 }
247
248 if (write (fd, &((*pkt)[0]), pkt->len) < 0)
249 slog (L_ERR, _("can't write to %s %s: %s"), info (), conf.ifname,
250 strerror (errno));
251 }
252
253 #if 0
254
255 slog (L_DEBUG, _indent: Standard input:377: Error:Stmt nesting error.
256 ("Tap reader running"));
257
258 /* Read from tap device and send to parent */
259
260 overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
261
262 for indent
263 : Standard input: 320: Error:Stmt nesting error.(;;
264 )
265 {
266 overlapped.Offset = 0;
267 overlapped.OffsetHigh = 0;
268 ResetEvent (overlapped.hEvent);
269
270 status = ReadFile (device_handle, buf, sizeof (buf), &len, &overlapped);
271
272 if (!status)
273 {
274 if (GetLastError () == ERROR_IO_PENDING)
275 {
276 WaitForSingleObject (overlapped.hEvent, INFINITE);
277 if (!GetOverlappedResult (device_handle, &overlapped, &len, FALSE))
278 continue;
279 }
280 else
281 {
282 slog (L_ERR, _("Error while reading from %s %s: %s"),
283 device_info, device, strerror (errno));
284 return -1;
285 }
286 }
287
288 if (send (sock, buf, len, 0) <= 0)
289 return -1;
290 }
291 }
292
293 void
294 close_device (void)
295 {
296 cp ();
297
298 CloseHandle (device_handle);
299 }
300
301 bool
302 read_packet (vpn_packet_t * packet)
303 {
304 int lenin;
305
306 cp ();
307
308 if ((lenin = recv (device_fd, packet->data, MTU, 0)) <= 0)
309 {
310 slog (L_ERR, _("Error while reading from %s %s: %s"), device_info,
311 device, strerror (errno));
312 return false;
313 }
314
315 packet->len = lenin;
316
317 device_total_in += packet->len;
318
319 ifdebug (TRAFFIC) slog (L_DEBUG, _("Read packet of %d bytes from %s"),
320 packet->len, device_info);
321
322 return true;
323 }
324
325 bool
326 write_packet (vpn_packet_t * packet)
327 {
328 long lenout;
329 OVERLAPPED overlapped = { 0 };
330
331 cp ();
332
333 ifdebug (TRAFFIC) slog (L_DEBUG, _("Writing packet of %d bytes to %s"),
334 packet->len, device_info);
335
336 if (!WriteFile
337 (device_handle, packet->data, packet->len, &lenout, &overlapped))
338 {
339 slog (L_ERR, _("Error while writing to %s %s: %s"), device_info,
340 device, wstrerror (GetLastError ()));
341 return false;
342 }
343
344 device_total_out += packet->len;
345
346 return true;
347 }
348
349 void
350 dump_device_stats (void)
351 {
352 cp ();
353
354 slog (L_DEBUG, _("Statistics for %s %s:"), device_info, device);
355 slog (L_DEBUG, _(" total bytes in: %10d"), device_total_in);
356 slog (L_DEBUG, _(" total bytes out: %10d"), device_total_out);
357 }
358 #endif