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