1 #include "protoVif.h"
2 #include "protoNet.h"
3 #include "protoDebug.h"
4 #include "windows.h"
5 #include "common.h" // ljt why isn't it finding this in the
6 #include <Iphlpapi.h>
7 #include <stdio.h>
8
9 #include <winioctl.h>
10 // Where did these defines go?? Is this the right location? ljt
11 /* ===============================================
12 This file is included both by OpenVPN and
13 the TAP-Win32 driver and contains definitions
14 common to both.
15 =============================================== */
16
17 /* =============
18 TAP IOCTLs
19 ============= */
20
21 #define TAP_CONTROL_CODE(request,method) \
22 CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
23
24 #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
25 #define USERMODEDEVICEDIR "\\\\.\\Global\\"
26 #define NETWORK_CONNECTIONS_KEY \
27 "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
28 #define TAPSUFFIX ".tap"
29
30 class Win32Vif : public ProtoVif
31 {
32 public:
33 Win32Vif();
34 ~Win32Vif();
35
36 bool InitTap(char* vifName, const ProtoAddress& vifAddr, unsigned int maskLen);
37 bool ConfigureTap(char* adapterid, char* vifName, const ProtoAddress& vifAddr,unsigned int maskLen);
38 bool FindIPAddr(ProtoAddress vifAddr);
39
40 bool Open(const char* vifName, const ProtoAddress& vifAddr, unsigned int maskLen);
41
42 void Close();
43
44 bool Write(const char* buffer, unsigned int numBytes);
45
46 bool Read(char* buffer, unsigned int& numBytes);
47
48 private:
49 #ifndef _WIN32_WCE
50 // These members facilitate Win32 overlapped I/O
51 // which we use for async I/O
52 HANDLE tap_handle;
53 enum {BUFFER_MAX = 8192};
54 char read_buffer[BUFFER_MAX];
55 unsigned int read_count;
56 char write_buffer[BUFFER_MAX];
57 OVERLAPPED read_overlapped;
58 OVERLAPPED write_overlapped;
59
60 #endif // if _WIN32_WCE
61
62 }; // end class ProtoVif
63
Create()64 ProtoVif* ProtoVif::Create()
65 {
66 return static_cast<ProtoVif*>(new Win32Vif);
67
68 } // end ProtoVif::Create()
69
Win32Vif()70 Win32Vif::Win32Vif()
71 {
72 }
73
~Win32Vif()74 Win32Vif::~Win32Vif()
75 {
76 }
77
ConfigureTap(char * adapterid,char * vifName,ProtoAddress vifAddr,unsigned int maskLen)78 bool Win32Vif::ConfigureTap(char* adapterid,char* vifName,ProtoAddress vifAddr,unsigned int maskLen)
79 {
80 ULONG status;
81 HKEY key;
82 DWORD nameType;
83 const char nameString[] = "Name";
84 char regpath[1024];
85 char nameData[1024];
86 long len = sizeof(nameData);
87
88 /* Find out more about this adapter */
89 sprintf(regpath, "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
90
91 /* Open the adapter key */
92 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
93 regpath,
94 0,
95 KEY_READ,
96 &key);
97
98 if (status != ERROR_SUCCESS)
99 {
100 PLOG(PL_WARN,"Win32Vif::ConfigureTap() Error opening adapter registry key:%s\n",regpath);
101 return false;
102 }
103
104 /* Get the adapter name */
105 status = RegQueryValueEx(key,
106 nameString,
107 NULL,
108 &nameType,
109 (LPBYTE)nameData,
110 (LPDWORD)&len);
111
112 if (status != ERROR_SUCCESS) // ljt || nameType != REG_SZ)
113 {
114 PLOG(PL_ERROR,"Win32Vif::ConfigureTap() Error opening registry key: %s\n%s\n%s\n\n",
115 NETWORK_CONNECTIONS_KEY,regpath,"Name");
116 return false;;
117 }
118 RegCloseKey(key);
119
120 /* Configure the interface */
121 char cmd[256];
122 char subnetMask[16];
123
124 ProtoAddress subnetMaskAddr;
125 subnetMaskAddr.ResolveFromString("255.255.255.255");
126
127 ProtoAddress tmpAddr;
128 subnetMaskAddr.GetSubnetAddress(maskLen, tmpAddr);
129 sprintf(subnetMask," %s ", tmpAddr.GetHostString());
130
131 sprintf(cmd,
132 "netsh interface ip set address \"%s\" static %s %s ",
133 nameData, vifAddr.GetHostString(), subnetMask);
134
135 if (LONG ret = system(cmd))
136 {
137 PLOG(PL_ERROR,"Win32Vif::ConfigureTap(%s) Open failed. netsh call returned: %u", nameData, ret);
138 return false;
139 }
140
141 // Rename the connection
142 if (strcmp(nameData, vifName) != 0)
143 {
144 sprintf(cmd, "netsh interface set interface name=\"%s\" newname=\"%s\"",
145 nameData,vifName);
146 if (LONG ret = system(cmd))
147 {
148 PLOG(PL_ERROR,"Win32Vif::ConfigureTap(%s) Rename failed (%s). netsh call returned: %u",
149 nameData, vifName, ret);
150 return false;
151 }
152 }
153 PLOG(PL_INFO,"Win32Vif::ConfigureTap() Tap opened on interface: %s\n",vifName);
154
155 /* set driver media status to 'connected' */
156 status = TRUE;
157 if (!DeviceIoControl(tap_handle, TAP_IOCTL_SET_MEDIA_STATUS,
158 &status, sizeof (status),
159 &status, sizeof (status),
160 (LPDWORD)&len, NULL))
161 PLOG(PL_WARN, "Win32Vif::ConfigureTap() warning: The TAP-Win32 driver rejected a TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.");
162
163 return true;
164 } // end Win32Five::ConfigureTap()
165
InitTap(const char * vifName,const ProtoAddress & vifAddr,unsigned int maskLen)166 bool Win32Vif::InitTap(const char* vifName, const ProtoAddress& vifAddr, unsigned int maskLen)
167 {
168 HKEY key;
169 ULONG status;
170 char adapterid[1024];
171 char tapname[1024];
172 long len;
173
174 /// Open Registry and get a list of network adapters
175 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
176 NETWORK_CONNECTIONS_KEY,
177 0,
178 KEY_READ,
179 &key);
180
181 if (status != ERROR_SUCCESS)
182 {
183 PLOG(PL_ERROR,"Win32Vif::InitTap() Error opening registry key:%s\n",NETWORK_CONNECTIONS_KEY);
184 return false;
185 }
186
187 /* find the adapter with TAPSUFFIX */
188 for (int enum_index = 0; ; enum_index++)
189 {
190 len = sizeof(adapterid);
191 if (RegEnumKeyEx(key, enum_index, adapterid, (LPDWORD)&len,
192 NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
193 {
194 RegCloseKey(key);
195 PLOG(PL_ERROR,"Win32Vif::InitTap() error: Couldn't find TAP-Win32 adapter.\n");
196 return false;
197 }
198 sprintf(tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
199 // Get the tap handle
200 tap_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ,
201 0, 0, OPEN_EXISTING,
202 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
203
204 if (tap_handle != INVALID_HANDLE_VALUE)
205 {
206 break;
207 }
208 }
209
210 RegCloseKey(key);
211 PLOG(PL_INFO,"win32Vif::InitTap() found tap adapter %s\n",tapname);
212
213 if (!ConfigureTap(adapterid,vifName,vifAddr,maskLen))
214 return false;
215
216 if (NULL == (input_handle = CreateEvent(NULL,TRUE,FALSE,NULL)))
217 {
218 input_handle = INVALID_HANDLE_VALUE;
219 PLOG(PL_ERROR,"Win32Vif::InitTap() CreateEvent(input_handle) error: %s\n", ::GetErrorString());
220 Close(); // ljt??
221 return false;
222 }
223 if (NULL == (output_handle = CreateEvent(NULL,TRUE,FALSE,NULL)))
224 {
225 output_handle = INVALID_HANDLE_VALUE;
226 PLOG(PL_ERROR,"Win32Vif::InitTap() CreateEvent(output_handle) error: %s\n",::GetErrorString());
227 Close(); // ljt??
228 return false;
229 }
230
231 memset(&read_overlapped,0,sizeof(read_overlapped));
232 read_overlapped.hEvent = input_handle;
233 memset(&write_overlapped,0,sizeof(write_overlapped));
234 write_overlapped.hEvent = output_handle;
235
236 StartInputNotification();
237
238 // Start overlapped notifications
239 if (NULL != GetNotifier())
240 {
241 // Initiate overlapped I/O ...
242 DWORD bytesRead;
243 if (0 != ReadFile(tap_handle, read_buffer, BUFFER_MAX, &bytesRead, &read_overlapped))
244 {
245 input_ready = true;
246 read_count = bytesRead;
247 }
248 else
249 {
250 switch(GetLastError())
251 {
252 case ERROR_IO_PENDING:
253 read_count = 0;
254 input_ready = false;
255 break;
256 //case ERROR_BROKEN_PIPE:
257 default:
258 PLOG(PL_ERROR,"Win32Vif::InitTap() ReadFile() error: %s\n", ::GetErrorString());
259 Close();
260 return false;
261 }
262 }
263 }
264
265 if (!UpdateNotification())
266 {
267 PLOG(PL_ERROR, "Win32Vif::InitTap() error updating notification\n");
268 Close();
269 return false;
270 }
271
272 return true;
273
274 } // end Win32Vif::InitTap()
275
Open(const char * vifName,const ProtoAddress & vifAddr,unsigned int maskLen)276 bool Win32Vif::Open(const char* vifName, const ProtoAddress& vifAddr, unsigned int maskLen)
277 {
278 if (!InitTap(vifName, vifAddr, maskLen))
279 {
280 PLOG(PL_ERROR,"Win32Vif::Open(%s) error: open failed: %s\n",vifName, GetErrorString());
281 return false;
282 }
283 strncpy(vif_name, vifName, VIF_NAME_MAX);
284
285 // Snag the virtual interface hardware address
286 if (!ProtoNet::GetInterfaceAddress(vifName, ProtoAddress::ETH, hw_addr))
287 PLOG(PL_ERROR, "Win32Vif::Open(%s) error: unable to get ETH address!\n", vifName);
288
289 if (!ProtoChannel::Open())
290 {
291 PLOG(PL_ERROR, "Win32Vif::Open(%s) error: couldn't install ProtoChannel\n", vifName);
292 Close();
293 return false;
294 }
295 else
296 {
297 return true;
298 }
299 } // end Win32Vif::Open()
300
Close()301 void Win32Vif::Close()
302 {
303 ProtoChannel::Close();
304 if (INVALID_HANDLE_VALUE != tap_handle)
305 {
306 CloseHandle(tap_handle);
307 tap_handle = INVALID_HANDLE_VALUE;
308 }
309 if (INVALID_HANDLE_VALUE != input_handle)
310 {
311 CloseHandle(input_handle);
312 input_handle = INVALID_HANDLE_VALUE;
313 }
314 if (INVALID_HANDLE_VALUE != output_handle)
315 {
316 CloseHandle(output_handle);
317 output_handle = INVALID_HANDLE_VALUE;
318 }
319 output_ready = input_ready = false;
320
321 } // end Win32Vif::Close()
322
Write(const char * buffer,unsigned int numBytes)323 bool Win32Vif::Write(const char* buffer, unsigned int numBytes)
324 {
325 // ljt is this quite right??
326
327 DWORD bytesWritten = 0;
328 OVERLAPPED overlappedPtr;
329
330 // set up overlapped structure fields
331 overlappedPtr.Offset = 0;
332 overlappedPtr.OffsetHigh = 0;
333 overlappedPtr.hEvent = NULL;
334
335 const char* bufPtr = buffer;
336
337 if (NULL != GetNotifier())
338 {
339 if (!output_ready)
340 {
341 if (FALSE != GetOverlappedResult(tap_handle,&write_overlapped,&bytesWritten,FALSE))
342 {
343 output_ready = true;
344 overlappedPtr = write_overlapped;
345 bufPtr = write_buffer;
346 if (numBytes > BUFFER_MAX) numBytes = BUFFER_MAX;
347 memcpy(write_buffer,buffer,numBytes);
348 }
349 else
350 {
351 if (GetDebugLevel() >= 2)
352 PLOG(PL_ERROR,"Win32Vif::Write() GetOverlappedResult() error: %s\n",::GetErrorString());
353 return false;
354 }
355 }
356 }
357
358 if (0 != WriteFile(tap_handle,bufPtr,numBytes,&bytesWritten,(LPOVERLAPPED)&overlappedPtr))
359 {
360 numBytes = bytesWritten;
361 if (0 == numBytes)
362 {
363 output_ready = false;
364 }
365 return true;
366 }
367 else
368 {
369 numBytes = 0;
370 switch (GetLastError())
371 {
372 case ERROR_IO_PENDING:
373 return true;
374 case ERROR_BROKEN_PIPE:
375 OnNotify(NOTIFY_NONE);
376 break;
377 default:
378 PLOG(PL_ERROR,"Win32Vif::Write() WriteFile() error(%d): %s\n",GetLastError(),::GetErrorString());
379 break;
380 }
381 return false;
382 }
383
384 return true;
385 } // end Win32Vif::Write()
386
Read(char * buffer,unsigned int & numBytes)387 bool Win32Vif::Read(char* buffer, unsigned int& numBytes)
388 {
389
390 DWORD bytesRead = 0;
391 unsigned int len = 0;
392 if (NULL != GetNotifier())
393 {
394 if (!input_ready)
395 {
396 // We had a pending overlapped read operation
397 if (FALSE != GetOverlappedResult(tap_handle,&read_overlapped,&bytesRead,FALSE))
398 {
399 numBytes = read_count = bytesRead;
400 memcpy(buffer,read_buffer,bytesRead);
401 input_ready = true;
402 }
403 else
404 {
405 numBytes = 0;
406 switch (GetLastError())
407 {
408 case ERROR_BROKEN_PIPE:
409 OnNotify(NOTIFY_NONE);
410 return false;
411 default:
412 PLOG(PL_ERROR,"Win32Vif::Read() GetOverlappedResult() error (%d): %s\n",GetLastError(), ::GetErrorString());
413 return false;
414 }
415 }
416 }
417 }
418 // Do we have any data in our "read_buffer"?
419 if (read_count > 0)
420 {
421 memcpy (buffer,read_buffer,read_count);
422 numBytes = read_count;
423 read_count = 0;
424 return true;
425 }
426
427 // Read more as needed, triggering overlapped I/O
428 memset(&read_overlapped,0,sizeof(read_overlapped));
429 read_overlapped.hEvent = input_handle;
430 memset(&write_overlapped,0,sizeof(write_overlapped));
431 write_overlapped.hEvent = output_handle; // ljt need me?
432
433 bytesRead = 0;
434 len = BUFFER_MAX;
435 if (0 != ReadFile(tap_handle,read_buffer,len,&bytesRead,&read_overlapped))
436 {
437 memcpy(buffer,read_buffer,bytesRead);
438 numBytes = bytesRead;
439 input_ready = true;
440 }
441 else
442 {
443 switch(GetLastError())
444 {
445 case ERROR_IO_PENDING:
446 read_count = 0;
447 input_ready = false;
448 break;
449 case ERROR_BROKEN_PIPE:
450 if (0 == bytesRead)
451 {
452 OnNotify(NOTIFY_NONE);
453 return false;
454 }
455 break;
456 default:
457 PLOG(PL_ERROR,"Win32Vif::Read() error: %s\n", ::GetErrorString());
458 if (0 == bytesRead) return false;
459 break;
460 }
461 }
462
463 numBytes = bytesRead;
464 return true;
465 } // end Win32Vif::Read()
466
FindIPAddr(ProtoAddress vifAddr)467 bool Win32Vif::FindIPAddr(ProtoAddress vifAddr)
468 {
469 // Iterate through addresses looking for an address match
470 ULONG bufferSize = 0;
471 ULONG index = 0;
472 if (ERROR_INSUFFICIENT_BUFFER == GetIpAddrTable(NULL, &bufferSize, FALSE))
473 {
474 char* tableBuffer = new char[bufferSize];
475 if (NULL == tableBuffer)
476 {
477 PLOG(PL_ERROR, "ProtoSocket::GetInterfaceName() new tableBuffer error: %s\n", ::GetErrorString());
478 return false;
479 }
480 MIB_IPADDRTABLE* addrTable = (MIB_IPADDRTABLE*)tableBuffer;
481 if (ERROR_SUCCESS == GetIpAddrTable(addrTable, &bufferSize, FALSE))
482 {
483 for (DWORD i = 0; i < addrTable->dwNumEntries; i++)
484 {
485 MIB_IPADDRROW* entry = &(addrTable->table[i]);
486 ProtoAddress tempAddress;
487 tempAddress.SetRawHostAddress(ProtoAddress::IPv4, (char*)&entry->dwAddr, 4);
488 if (tempAddress.HostIsEqual(vifAddr))
489 {
490 return true; // ljt fix me
491 MIB_IFROW ifEntry;
492 index = entry->dwIndex;
493 if (NO_ERROR != GetIfEntry(&ifEntry))
494 {
495 PLOG(PL_ERROR, "ProtoSocket::GetInterfaceName() GetIfEntry(%d) error: %s\n", i, ::GetErrorString());
496 return false;
497 }
498 delete[] tableBuffer;
499 break;
500 }
501 }
502 }
503 else
504 {
505 PLOG(PL_WARN, "ProtoSocket::GetInterfaceName(%s) warning GetIpAddrTable() error: %s\n", vifAddr.GetHostString(), GetErrorString());
506 }
507 delete[] tableBuffer;
508 }
509
510 if (index)
511 {
512 // we found one - add another address
513 // ljt need to check if this is a vif etc
514 // maybe don't do this at all? just fail
515 // if we've found one?
516
517 ULONG status = TRUE;
518 UINT tmpIPAddr;
519 UINT tmpIPMask;
520 ULONG NTEContext = 0;
521 ULONG NTEInstance = 0;
522 tmpIPAddr = inet_addr(vifAddr.GetHostString());
523 tmpIPMask = inet_addr("255.255.255.0");
524 if ((status = AddIPAddress(tmpIPAddr,
525 tmpIPMask,
526 index,
527 &NTEContext,
528 &NTEInstance)) != NO_ERROR)
529 {
530 PLOG(PL_ERROR,"Win32Vif::Open() AddIPAddress call failed with %d\n",status);
531 return false;
532 }
533 return true;
534 }
535 return false;
536 } // end Win32Vif::FindIPAddr()
537