Imported Upstream version 0.3.5
[anytun.git] / src / win32 / tunDevice.cpp
1 /*
2  *  anytun
3  *
4  *  The secure anycast tunneling protocol (satp) defines a protocol used
5  *  for communication between any combination of unicast and anycast
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
8  *  ethernet, ip, arp ...). satp directly includes cryptography and
9  *  message authentication based on the methods used by SRTP.  It is
10  *  intended to deliver a generic, scaleable and secure solution for
11  *  tunneling and relaying of packets of any protocol.
12  *
13  *
14  *  Copyright (C) 2007-2014 Markus Grüneis, Othmar Gsenger, Erwin Nindl,
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
19  *  Anytun is free software: you can redistribute it and/or modify
20  *  it under the terms of the GNU General Public License as published by
21  *  the Free Software Foundation, either version 3 of the License, or
22  *  any later version.
23  *
24  *  Anytun is distributed in the hope that it will be useful,
25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *  GNU General Public License for more details.
28  *
29  *  You should have received a copy of the GNU General Public License
30  *  along with Anytun.  If not, see <http://www.gnu.org/licenses/>.
31  *
32  *  In addition, as a special exception, the copyright holders give
33  *  permission to link the code of portions of this program with the
34  *  OpenSSL library under certain conditions as described in each
35  *  individual source file, and distribute linked combinations
36  *  including the two.
37  *  You must obey the GNU General Public License in all respects
38  *  for all of the code used other than OpenSSL.  If you modify
39  *  file(s) with this exception, you may extend this exception to your
40  *  version of the file(s), but you are not obligated to do so.  If you
41  *  do not wish to do so, delete this exception statement from your
42  *  version.  If you delete this exception statement from all source
43  *  files in the program, then also delete it here.
44  */
45
46 #include <string.h>
47 #include <sstream>
48 #include <windows.h>
49 #include <winioctl.h>
50
51 #include "../endian.h"
52 #include "../tunDevice.h"
53 #include "../threadUtils.hpp"
54 #include "../log.h"
55 #include "../anytunError.h"
56
57 #include "registryKey.h"
58 #include "common.h"
59
60 #define MIN_TAP_VER_MAJOR 8
61 #define MIN_TAP_VER_MINOR 2
62
63 TunDevice::TunDevice(std::string dev_name, std::string dev_type, std::string ifcfg_addr, uint16_t ifcfg_prefix) : conf_(dev_name, dev_type, ifcfg_addr, ifcfg_prefix, 1400)
64 {
65   if(conf_.type_ != TYPE_TUN && conf_.type_ != TYPE_TAP) {
66     AnytunError::throwErr() << "unable to recognize type of device (tun or tap)";
67   }
68
69   handle_ = INVALID_HANDLE_VALUE;
70   if(!getAdapter(dev_name)) {
71     AnytunError::throwErr() << "can't find any suitable device";
72   }
73
74   if(handle_ == INVALID_HANDLE_VALUE) {
75     std::stringstream tapname;
76     tapname << USERMODEDEVICEDIR << actual_node_ << TAPSUFFIX;
77     handle_ = CreateFileA(tapname.str().c_str(), GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
78     if(handle_ == INVALID_HANDLE_VALUE) {
79       AnytunError::throwErr() << "Unable to open device: " << actual_node_ << " (" << actual_name_ << "): " << AnytunErrno(GetLastError());
80     }
81   }
82
83   DWORD err;
84   u_long info[3];
85   info[0] = info[1] = info[2] = 0;
86   err = performIoControl(TAP_IOCTL_GET_VERSION, info, sizeof(info), info, sizeof(info));
87   if(err != ERROR_SUCCESS) {
88     CloseHandle(handle_);
89     AnytunError::throwErr() << "Unable to get device version: " << AnytunErrno(err);
90   }
91   cLog.msg(Log::PRIO_NOTICE) << "Windows TAP Driver Version " << info[0] << "." << info[1] << " " << (info[2] ? "(DEBUG)" : "");
92   if(!(info[0] > MIN_TAP_VER_MAJOR || (info[0] == MIN_TAP_VER_MAJOR && info[1] >= MIN_TAP_VER_MINOR))) {
93     CloseHandle(handle_);
94     AnytunError::throwErr() << "need a higher Version of TAP Driver (at least " << MIN_TAP_VER_MAJOR << "." << MIN_TAP_VER_MINOR << ")";
95   }
96
97   if(conf_.type_ == TYPE_TUN) {
98     u_long ep[3];
99     ep[0] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong());
100     ep[1] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong() & conf_.netmask_.getNetworkAddressV4().to_ulong());
101     ep[2] = htonl(conf_.netmask_.getNetworkAddressV4().to_ulong());
102     err = performIoControl(TAP_IOCTL_CONFIG_TUN, ep, sizeof(ep), ep, sizeof(ep));
103     if(err != ERROR_SUCCESS) {
104       CloseHandle(handle_);
105       AnytunError::throwErr() << "Unable to set device tun mode: " << AnytunErrno(err);
106     }
107   }
108
109   if(ifcfg_addr != "") {
110     do_ifconfig();
111   }
112
113   int status = true;
114   err = performIoControl(TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status));
115   if(err != ERROR_SUCCESS) {
116     CloseHandle(handle_);
117     AnytunError::throwErr() << "Unable to set device media status: " << AnytunErrno(err);
118   }
119
120   roverlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
121   woverlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
122 }
123
124 bool TunDevice::getAdapter(std::string const& dev_name)
125 {
126   RegistryKey akey;
127   DWORD err = akey.open(HKEY_LOCAL_MACHINE, ADAPTER_KEY, KEY_ENUMERATE_SUB_KEYS);
128   if(err != ERROR_SUCCESS) {
129     AnytunError::throwErr() << "Unable to open registry key (HKLM\\" << ADAPTER_KEY << "): " << AnytunErrno(err);
130   }
131
132   bool found = false;
133   for(int i=0; ; ++i) {
134     RegistryKey ckey;
135     DWORD err = akey.getSubKey(i, ckey, KEY_QUERY_VALUE);
136     if(err == ERROR_NO_MORE_ITEMS) {
137       break;
138     }
139     if(err != ERROR_SUCCESS) {
140       continue;
141     }
142
143     try {
144       if(ckey["ComponentId"] != TAP_COMPONENT_ID) {
145         continue;
146       }
147       actual_node_ = ckey["NetCfgInstanceId"];
148
149       RegistryKey nkey;
150       std::stringstream keyname;
151       keyname << NETWORK_CONNECTIONS_KEY << "\\" << actual_node_ << "\\Connection";
152       err = nkey.open(HKEY_LOCAL_MACHINE, keyname.str().c_str(), KEY_QUERY_VALUE);;
153       if(err != ERROR_SUCCESS) {
154         continue;
155       }
156
157       actual_name_ = nkey["Name"];
158     } catch(AnytunErrno&) { continue; }
159
160     if(dev_name != "") {
161       if(dev_name == actual_name_) {
162         found = true;
163         break;
164       }
165     } else {
166       std::stringstream tapname;
167       tapname << USERMODEDEVICEDIR << actual_node_ << TAPSUFFIX;
168       handle_ = CreateFileA(tapname.str().c_str(), GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
169       if(handle_ == INVALID_HANDLE_VALUE) {
170         continue;
171       }
172       found = true;
173       break;
174     }
175   }
176   if(!found) {
177     actual_node_ = "";
178     actual_name_ = "";
179   }
180   return found;
181 }
182
183 DWORD TunDevice::performIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inBufferSize, LPVOID outBuffer, DWORD outBufferSize)
184 {
185   OVERLAPPED overlapped;
186   overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
187   overlapped.Offset = 0;
188   overlapped.OffsetHigh = 0;
189
190   DWORD len;
191   if(!DeviceIoControl(handle_, controlCode, inBuffer, inBufferSize, outBuffer, outBufferSize, &len, &overlapped)) {
192     DWORD err = GetLastError();
193     if(err == ERROR_IO_PENDING) {
194       WaitForSingleObject(overlapped.hEvent, INFINITE);
195       if(!GetOverlappedResult(handle_, &overlapped, &len, FALSE)) {
196         return GetLastError();
197       }
198     } else {
199       return GetLastError();
200     }
201   }
202   return ERROR_SUCCESS;
203 }
204
205
206 TunDevice::~TunDevice()
207 {
208   if(handle_ != INVALID_HANDLE_VALUE) {
209     CloseHandle(handle_);
210   }
211   if(roverlapped_.hEvent != INVALID_HANDLE_VALUE) {
212     CloseHandle(roverlapped_.hEvent);
213   }
214   if(woverlapped_.hEvent != INVALID_HANDLE_VALUE) {
215     CloseHandle(woverlapped_.hEvent);
216   }
217 }
218
219 int TunDevice::fix_return(int ret, size_t pi_length) const
220 {
221   // nothing to be done here
222   return 0;
223 }
224
225 int TunDevice::read(uint8_t* buf, uint32_t len)
226 {
227   DWORD lenout;
228   roverlapped_.Offset = 0;
229   roverlapped_.OffsetHigh = 0;
230   ResetEvent(roverlapped_.hEvent);
231
232   if(!ReadFile(handle_, buf, len, &lenout, &roverlapped_)) {
233     DWORD err = GetLastError();
234     if(err == ERROR_IO_PENDING) {
235       WaitForSingleObject(roverlapped_.hEvent, INFINITE);
236       if(!GetOverlappedResult(handle_, &roverlapped_, &lenout, FALSE)) {
237         cLog.msg(Log::PRIO_ERROR) << "Error while trying to get overlapped result: " << AnytunErrno(GetLastError());
238         return -1;
239       }
240     } else {
241       cLog.msg(Log::PRIO_ERROR) << "Error while reading from device: " << AnytunErrno(GetLastError());
242       return -1;
243     }
244   }
245   return lenout;
246 }
247
248 int TunDevice::write(uint8_t* buf, uint32_t len)
249 {
250   DWORD lenout;
251   woverlapped_.Offset = 0;
252   woverlapped_.OffsetHigh = 0;
253   ResetEvent(woverlapped_.hEvent);
254
255   if(!WriteFile(handle_, buf, len, &lenout, &woverlapped_)) {
256     DWORD err = GetLastError();
257     if(err == ERROR_IO_PENDING) {
258       WaitForSingleObject(woverlapped_.hEvent, INFINITE);
259       if(!GetOverlappedResult(handle_, &woverlapped_, &lenout, FALSE)) {
260         cLog.msg(Log::PRIO_ERROR) << "Error while trying to get overlapped result: " << AnytunErrno(GetLastError());
261         return -1;
262       }
263     } else {
264       cLog.msg(Log::PRIO_ERROR) << "Error while writing to device: " << AnytunErrno(GetLastError());
265       return -1;
266     }
267   }
268   return lenout;
269 }
270
271 void TunDevice::init_post()
272 {
273   // nothing to be done here
274 }
275
276 void TunDevice::do_ifconfig()
277 {
278   u_long ep[4];
279   ep[0] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong());
280   ep[1] = htonl(conf_.netmask_.getNetworkAddressV4().to_ulong());
281   ep[2] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong() & conf_.netmask_.getNetworkAddressV4().to_ulong());
282   ep[3] = 365 * 24 * 3600;  // lease time in seconds
283   DWORD err = performIoControl(TAP_IOCTL_CONFIG_DHCP_MASQ, ep, sizeof(ep), ep, sizeof(ep));
284   if(err != ERROR_SUCCESS) {
285     CloseHandle(handle_);
286     AnytunError::throwErr() << "Unable to set device dhcp masq mode: " << AnytunErrno(err);
287   }
288
289   u_long mtu;
290   err = performIoControl(TAP_IOCTL_GET_MTU, &mtu, sizeof(mtu), &mtu, sizeof(mtu));
291   if(err != ERROR_SUCCESS) {
292     CloseHandle(handle_);
293     AnytunError::throwErr() << "Unable to get device mtu: " << AnytunErrno(err);
294   }
295   conf_.mtu_ = static_cast<uint16_t>(mtu);
296 }
297
298 void TunDevice::waitUntilReady()
299 {
300   // nothing to be done here
301 }