1 /*
2   (C) 2007-09 - Luca Deri <deri@ntop.org>
3 */
4 
5 #include "n2n.h"
6 #include "n2n_win32.h"
7 
8 /* ***************************************************** */
9 
initWin32()10 void initWin32() {
11   WSADATA wsaData;
12   int err;
13 
14   err = WSAStartup(MAKEWORD(2, 2), &wsaData );
15   if( err != 0 ) {
16     /* Tell the user that we could not find a usable */
17     /* WinSock DLL.                                  */
18     printf("FATAL ERROR: unable to initialise Winsock 2.x.");
19     exit(EXIT_FAILURE);
20   }
21 }
22 
23 struct win_adapter_info {
24   HANDLE handle;
25   char adapterid[1024];
26   char adaptername[1024];
27 };
28 
29 /* ***************************************************** */
30 
open_tap_device(const char * adapterid)31 static HANDLE open_tap_device(const char *adapterid) {
32   char tapname[1024];
33   _snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
34 
35   return(CreateFile(tapname, GENERIC_WRITE | GENERIC_READ,
36                0, /* Don't let other processes share or open
37                the resource until the handle's been closed */
38                0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0));
39 }
40 
41 /* ***************************************************** */
42 
iterate_win_network_adapters(int (* callback)(struct win_adapter_info *,struct tuntap_dev *),void * userdata)43 static void iterate_win_network_adapters(
44     int (*callback)(struct win_adapter_info*, struct tuntap_dev *),
45     void *userdata) {
46   HKEY key, key2;
47   char regpath[1024];
48   long len, rc;
49   int found = 0;
50   int err, i;
51   struct win_adapter_info adapter;
52 
53   /* Open registry and look for network adapters */
54   if((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key))) {
55     printf("Unable to read registry: [rc=%d]\n", rc);
56     exit(EXIT_FAILURE);
57     /* MSVC Note: If you keep getting rc=2 errors, make sure you set:
58        Project -> Properties -> Configuration Properties -> General -> Character set
59        to: "Use Multi-Byte Character Set"
60     */
61   }
62 
63   for (i = 0; ; i++) {
64     len = sizeof(adapter.adapterid);
65     if(RegEnumKeyEx(key, i, (LPTSTR)adapter.adapterid, &len, 0, 0, 0, NULL))
66       break;
67 
68     /* Find out more about this adapter */
69 
70     _snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapter.adapterid);
71     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)regpath, 0, KEY_READ, &key2))
72       continue;
73 
74     len = sizeof(adapter.adaptername);
75     err = RegQueryValueEx(key2, "Name", 0, 0, adapter.adaptername, &len);
76 
77     RegCloseKey(key2);
78 
79     if(err)
80       continue;
81 
82 
83     adapter.handle = open_tap_device(adapter.adapterid);
84 
85     if(adapter.handle != INVALID_HANDLE_VALUE) {
86       /* Valid device, use the callback */
87       if(!callback(&adapter, userdata))
88         break;
89       else
90         CloseHandle(adapter.handle);
91       /* continue */
92     }
93   }
94 
95   RegCloseKey(key);
96 }
97 
98 /* ***************************************************** */
99 
print_adapter_callback(struct win_adapter_info * adapter,struct tuntap_dev * device)100 static int print_adapter_callback(struct win_adapter_info *adapter, struct tuntap_dev *device) {
101   printf("  %s - %s\n", adapter->adapterid, adapter->adaptername);
102 
103   /* continue */
104   return(1);
105 }
106 
win_print_available_adapters()107 void win_print_available_adapters() {
108   iterate_win_network_adapters(print_adapter_callback, NULL);
109 }
110 
111 /* ***************************************************** */
112 
lookup_adapter_info_reg(const char * target_adapter,char * regpath,size_t regpath_size)113 static int lookup_adapter_info_reg(const char *target_adapter, char *regpath, size_t regpath_size) {
114   HKEY key, key2;
115   long len, rc;
116   char index[16];
117   int err, i;
118   char adapter_name[N2N_IFNAMSIZ];
119   int rv = 0;
120 
121   if((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_INFO_KEY, 0, KEY_READ, &key))) {
122     printf("Unable to read registry: %s, [rc=%d]\n", ADAPTER_INFO_KEY, rc);
123     exit(EXIT_FAILURE);
124   }
125 
126   for(i = 0; ; i++) {
127     len = sizeof(index);
128     if(RegEnumKeyEx(key, i, (LPTSTR)index, &len, 0, 0, 0, NULL))
129       break;
130 
131     _snprintf(regpath, regpath_size, "%s\\%s", ADAPTER_INFO_KEY, index);
132     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)regpath, 0, KEY_READ, &key2))
133       continue;
134 
135     len = sizeof(adapter_name);
136     err = RegQueryValueEx(key2, "NetCfgInstanceId", 0, 0, adapter_name, &len);
137 
138     RegCloseKey(key2);
139 
140     if(err)
141       continue;
142 
143     if(!strcmp(adapter_name, target_adapter)) {
144       rv = 1;
145       break;
146     }
147   }
148 
149   RegCloseKey(key);
150   return(rv);
151 }
152 
153 /* ***************************************************** */
154 
set_interface_mac(struct tuntap_dev * device,const char * mac_str)155 static void set_interface_mac(struct tuntap_dev *device, const char *mac_str) {
156   char cmd[256];
157   char mac_buf[18];
158   char adapter_info_reg[1024];
159 
160   uint64_t mac = 0;
161   uint8_t *ptr = (uint8_t*)&mac;
162 
163   if(strlen(mac_str) != 17) {
164     printf("Invalid MAC: %s\n", mac_str);
165     exit(EXIT_FAILURE);
166   }
167 
168   /* Remove the colons */
169   for(int i=0; i<6; i++) {
170     mac_buf[i*2] = mac_str[2*i + i];
171     mac_buf[i*2+1] = mac_str[2*i + i + 1];
172   }
173   mac_buf[12] = '\0';
174 
175   if(!lookup_adapter_info_reg(device->device_name, adapter_info_reg, sizeof(adapter_info_reg))) {
176     printf("Could not determine adapter MAC registry key\n");
177     exit(EXIT_FAILURE);
178   }
179 
180   _snprintf(cmd, sizeof(cmd),
181       "reg add HKEY_LOCAL_MACHINE\\%s /v MAC /d %s /f > nul", adapter_info_reg, mac_buf);
182   system(cmd);
183 
184   /* Put down then up again to apply */
185   CloseHandle(device->device_handle);
186   _snprintf(cmd, sizeof(cmd), "netsh interface set interface \"%s\" disabled > nul", device->ifName);
187   system(cmd);
188   _snprintf(cmd, sizeof(cmd), "netsh interface set interface \"%s\" enabled > nul", device->ifName);
189   system(cmd);
190 
191   device->device_handle = open_tap_device(device->device_name);
192   if(device->device_handle == INVALID_HANDLE_VALUE) {
193     printf("Reopening TAP device \"%s\" failed\n", device->device_name);
194     exit(EXIT_FAILURE);
195   }
196 }
197 
198 /* ***************************************************** */
199 
choose_adapter_callback(struct win_adapter_info * adapter,struct tuntap_dev * device)200 static int choose_adapter_callback(struct win_adapter_info *adapter, struct tuntap_dev *device) {
201   if(device->device_name) {
202     /* A device name filter was set, name must match */
203     if(strcmp(device->device_name, adapter->adapterid) &&
204        strcmp(device->device_name, adapter->adaptername)) {
205       /* Not found, continue */
206       return(1);
207     }
208   } /* otherwise just pick the first available adapter */
209 
210   /* Adapter found, break */
211   device->device_handle = adapter->handle;
212   if(device->device_name) free(device->device_name);
213   device->device_name = _strdup(adapter->adapterid);
214   device->ifName = _strdup(adapter->adaptername);
215   return(0);
216 }
217 
218 /* ***************************************************** */
219 
open_wintap(struct tuntap_dev * device,const char * devname,const char * address_mode,char * device_ip,char * device_mask,const char * device_mac,int mtu)220 int open_wintap(struct tuntap_dev *device,
221                 const char * devname,
222                 const char * address_mode, /* "static" or "dhcp" */
223                 char *device_ip,
224                 char *device_mask,
225                 const char *device_mac,
226                 int mtu) {
227   char cmd[256];
228   DWORD len;
229   ULONG status = TRUE;
230 
231   memset(device, 0, sizeof(struct tuntap_dev));
232   device->device_handle = INVALID_HANDLE_VALUE;
233   device->device_name = devname[0] ? _strdup(devname) : NULL;
234   device->ifName = NULL;
235   device->ip_addr = inet_addr(device_ip);
236 
237   iterate_win_network_adapters(choose_adapter_callback, device);
238 
239   if(device->device_handle == INVALID_HANDLE_VALUE) {
240     if(!devname[0])
241       printf("No Windows tap devices found, did you run tapinstall.exe?\n");
242     else
243       printf("Cannot find tap device \"%s\"\n", devname);
244     return -1;
245   }
246 
247   /* ************************************** */
248 
249   if(device_mac[0])
250     set_interface_mac(device, device_mac);
251 
252     /* Get MAC address from tap device->device_name */
253 
254   if(!DeviceIoControl(device->device_handle, TAP_IOCTL_GET_MAC,
255                       device->mac_addr, sizeof(device->mac_addr),
256                       device->mac_addr, sizeof(device->mac_addr), &len, 0)) {
257     printf("Could not get MAC address from Windows tap %s (%s)\n",
258            device->device_name, device->ifName);
259     return -1;
260   }
261 
262    device->mtu = mtu;
263 
264    printf("Open device [name=%s][ip=%s][ifName=%s][MTU=%d][mac=%02X:%02X:%02X:%02X:%02X:%02X]\n",
265 	 device->device_name, device_ip, device->ifName, device->mtu,
266 	 device->mac_addr[0] & 0xFF,
267 	 device->mac_addr[1] & 0xFF,
268 	 device->mac_addr[2] & 0xFF,
269 	 device->mac_addr[3] & 0xFF,
270 	 device->mac_addr[4] & 0xFF,
271 	 device->mac_addr[5] & 0xFF);
272 
273   /* ****************** */
274 
275   if ( 0 == strcmp("dhcp", address_mode) )
276   {
277       _snprintf(cmd, sizeof(cmd),
278                 "netsh interface ip set address \"%s\" dhcp > nul",
279                 device->ifName);
280   }
281   else
282   {
283       _snprintf(cmd, sizeof(cmd),
284                 "netsh interface ip set address \"%s\" static %s %s > nul",
285                 device->ifName, device_ip, device_mask);
286   }
287 
288   if(system(cmd) == 0) {
289     device->ip_addr = inet_addr(device_ip);
290     device->device_mask = inet_addr(device_mask);
291   } else
292     printf("WARNING: Unable to set device %s IP address [%s]\n",
293 			device->ifName, cmd);
294 
295   /* ****************** */
296 
297   /* MTU */
298   _snprintf(cmd, sizeof(cmd),
299     "netsh interface ipv4 set subinterface \"%s\" mtu=%d store=persistent > nul",
300     device->ifName, mtu);
301 
302   if(system(cmd) != 0)
303     printf("WARNING: Unable to set device %s MTU [%s]\n",
304       device->ifName, cmd);
305 
306   /* set driver media status to 'connected' (i.e. set the interface up) */
307   if (!DeviceIoControl (device->device_handle, TAP_IOCTL_SET_MEDIA_STATUS,
308 			&status, sizeof (status),
309 			&status, sizeof (status), &len, NULL))
310     printf("WARNING: Unable to enable TAP adapter\n");
311 
312   /*
313    * Initialize overlapped structures
314    */
315   device->overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
316   device->overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
317   if (!device->overlap_read.hEvent || !device->overlap_write.hEvent) {
318     return -1;
319   }
320 
321   return(0);
322 }
323 
324 /* ************************************************ */
325 
tuntap_read(struct tuntap_dev * tuntap,unsigned char * buf,int len)326 int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len)
327 {
328   DWORD read_size, last_err;
329 
330   ResetEvent(tuntap->overlap_read.hEvent);
331   if (ReadFile(tuntap->device_handle, buf, len, &read_size, &tuntap->overlap_read)) {
332     //printf("tun_read(len=%d)\n", read_size);
333     return read_size;
334   }
335   switch (last_err = GetLastError()) {
336   case ERROR_IO_PENDING:
337     WaitForSingleObject(tuntap->overlap_read.hEvent, INFINITE);
338     GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_read, &read_size, FALSE);
339     return read_size;
340     break;
341   default:
342     printf("GetLastError() returned %d\n", last_err);
343     break;
344   }
345 
346   return -1;
347 }
348 /* ************************************************ */
349 
tuntap_write(struct tuntap_dev * tuntap,unsigned char * buf,int len)350 int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len)
351 {
352   DWORD write_size;
353 
354   //printf("tun_write(len=%d)\n", len);
355 
356   ResetEvent(tuntap->overlap_write.hEvent);
357   if (WriteFile(tuntap->device_handle,
358 		buf,
359 		len,
360 		&write_size,
361 		&tuntap->overlap_write)) {
362     //printf("DONE tun_write(len=%d)\n", write_size);
363     return write_size;
364   }
365   switch (GetLastError()) {
366   case ERROR_IO_PENDING:
367     WaitForSingleObject(tuntap->overlap_write.hEvent, INFINITE);
368     GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_write,
369 			&write_size, FALSE);
370     return write_size;
371     break;
372   default:
373     break;
374   }
375 
376   return -1;
377 }
378 
379 /* ************************************************ */
380 
tuntap_open(struct tuntap_dev * device,char * dev,const char * address_mode,char * device_ip,char * device_mask,const char * device_mac,int mtu)381 int tuntap_open(struct tuntap_dev *device,
382                 char *dev,
383                 const char *address_mode, /* static or dhcp */
384                 char *device_ip,
385                 char *device_mask,
386                 const char * device_mac,
387                 int mtu) {
388     return(open_wintap(device, dev, address_mode, device_ip, device_mask, device_mac, mtu));
389 }
390 
391 /* ************************************************ */
392 
tuntap_close(struct tuntap_dev * tuntap)393 void tuntap_close(struct tuntap_dev *tuntap) {
394   CloseHandle(tuntap->device_handle);
395 }
396 
397 /* Fill out the ip_addr value from the interface. Called to pick up dynamic
398  * address changes. */
tuntap_get_address(struct tuntap_dev * tuntap)399 void tuntap_get_address(struct tuntap_dev *tuntap)
400 {
401 }
402 
403 /* ************************************************ */
404 
405 #if 0
406 int main(int argc, char* argv[]) {
407   struct tuntap_dev tuntap;
408   int i;
409   int mtu = 1400;
410 
411   printf("Welcome to n2n\n");
412   initWin32();
413   open_wintap(&tuntap, "static", "1.2.3.20", "255.255.255.0", mtu);
414 
415   for(i=0; i<10; i++) {
416     u_char buf[MTU];
417     int rc;
418 
419     rc = tun_read(&tuntap, buf, sizeof(buf));
420     buf[0]=2;
421     buf[1]=3;
422     buf[2]=4;
423 
424     printf("tun_read returned %d\n", rc);
425     rc = tun_write(&tuntap, buf, rc);
426     printf("tun_write returned %d\n", rc);
427   }
428   // rc = tun_open (device->device_name, IF_MODE_TUN);
429   WSACleanup ();
430   return(0);
431 }
432 
433 #endif
434