Imported Upstream version 0.3.3
[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 methodes 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-2009 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
33 #include <string.h>
34 #include <sstream>
35 #include <windows.h>
36 #include <winioctl.h>
37
38 #include "../endian.h"
39 #include "../tunDevice.h"
40 #include "../threadUtils.hpp"
41 #include "../log.h"
42 #include "../anytunError.h"
43
44 #include "registryKey.h"
45 #include "common.h"
46
47 #define MIN_TAP_VER_MAJOR 8
48 #define MIN_TAP_VER_MINOR 2
49
50 TunDevice::TunDevice(std::string dev_name, std::string dev_type, std::string ifcfg_addr, u_int16_t ifcfg_prefix) : conf_(dev_name, dev_type, ifcfg_addr, ifcfg_prefix, 1400)
51 {
52   if(conf_.type_ != TYPE_TUN && conf_.type_ != TYPE_TAP)
53     AnytunError::throwErr() << "unable to recognize type of device (tun or tap)";
54
55   handle_ = INVALID_HANDLE_VALUE;
56   if(!getAdapter(dev_name))
57     AnytunError::throwErr() << "can't find any suitable device";
58
59   if(handle_ == INVALID_HANDLE_VALUE) {
60     std::stringstream tapname;
61           tapname << USERMODEDEVICEDIR << actual_node_ << TAPSUFFIX;
62     handle_ = CreateFileA(tapname.str().c_str(), GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
63     if(handle_ == INVALID_HANDLE_VALUE)
64       AnytunError::throwErr() << "Unable to open device: " << actual_node_ << " (" << actual_name_ << "): " << AnytunErrno(GetLastError());
65   }
66
67   DWORD err;
68   u_long info[3];
69   info[0] = info[1] = info[2] = 0;
70   err = performIoControl(TAP_IOCTL_GET_VERSION, info, sizeof(info), info, sizeof(info));
71   if(err != ERROR_SUCCESS) {
72     CloseHandle(handle_);
73     AnytunError::throwErr() << "Unable to get device version: " << AnytunErrno(err);
74   }
75   cLog.msg(Log::PRIO_NOTICE) << "Windows TAP Driver Version " << info[0] << "." << info[1] << " " << (info[2] ? "(DEBUG)" : "");
76   if(!(info[0] > MIN_TAP_VER_MAJOR || (info[0] == MIN_TAP_VER_MAJOR && info[1] >= MIN_TAP_VER_MINOR))) {
77     CloseHandle(handle_);
78     AnytunError::throwErr() << "need a higher Version of TAP Driver (at least " << MIN_TAP_VER_MAJOR << "." << MIN_TAP_VER_MINOR << ")";
79   }
80
81   if(conf_.type_ == TYPE_TUN) {
82     u_long ep[3];
83     ep[0] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong());
84     ep[1] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong() & conf_.netmask_.getNetworkAddressV4().to_ulong());
85     ep[2] = htonl(conf_.netmask_.getNetworkAddressV4().to_ulong());
86     err = performIoControl(TAP_IOCTL_CONFIG_TUN, ep, sizeof(ep), ep, sizeof(ep));
87     if(err != ERROR_SUCCESS) {
88       CloseHandle(handle_);
89       AnytunError::throwErr() << "Unable to set device tun mode: " << AnytunErrno(err);
90     }
91   }
92
93   if(ifcfg_addr != "")
94     do_ifconfig();
95
96   int status = true;
97   err = performIoControl(TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status));
98   if(err != ERROR_SUCCESS) {
99     CloseHandle(handle_);
100     AnytunError::throwErr() << "Unable to set device media status: " << AnytunErrno(err);
101         }
102
103   roverlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
104   woverlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
105 }
106
107 bool TunDevice::getAdapter(std::string const& dev_name)
108 {
109   RegistryKey akey;
110   DWORD err = akey.open(HKEY_LOCAL_MACHINE, ADAPTER_KEY, KEY_ENUMERATE_SUB_KEYS);
111   if(err != ERROR_SUCCESS)
112     AnytunError::throwErr() << "Unable to open registry key (HKLM\\" << ADAPTER_KEY << "): " << AnytunErrno(err);
113   
114   bool found = false;
115   for(int i=0; ; ++i) {
116     RegistryKey ckey;
117     DWORD err = akey.getSubKey(i, ckey, KEY_QUERY_VALUE);
118     if(err == ERROR_NO_MORE_ITEMS)
119       break;
120     if(err != ERROR_SUCCESS)
121       continue;
122
123     try {
124           if(ckey["ComponentId"] != TAP_COMPONENT_ID)
125         continue;
126       actual_node_ = ckey["NetCfgInstanceId"];
127
128       RegistryKey nkey;
129       std::stringstream keyname;
130       keyname << NETWORK_CONNECTIONS_KEY << "\\" << actual_node_ << "\\Connection";
131       err = nkey.open(HKEY_LOCAL_MACHINE, keyname.str().c_str(), KEY_QUERY_VALUE);;
132       if(err != ERROR_SUCCESS)
133         continue;
134           
135           actual_name_ = nkey["Name"];
136         } catch(AnytunErrno&) { continue; }
137
138     if(dev_name != "") {
139       if(dev_name == actual_name_) {
140         found = true;
141         break;
142       }
143     }
144     else {
145       std::stringstream tapname;
146       tapname << USERMODEDEVICEDIR << actual_node_ << TAPSUFFIX;
147       handle_ = CreateFileA(tapname.str().c_str(), GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
148       if(handle_ == INVALID_HANDLE_VALUE)
149         continue;
150       found = true;
151       break;
152     }
153   }
154   if(!found) {
155     actual_node_ = "";
156     actual_name_ = "";
157   }
158   return found;
159 }
160
161 DWORD TunDevice::performIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inBufferSize, LPVOID outBuffer, DWORD outBufferSize)
162 {
163   OVERLAPPED overlapped;
164   overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
165   overlapped.Offset = 0;
166         overlapped.OffsetHigh = 0;
167   
168   DWORD len;
169   if(!DeviceIoControl(handle_, controlCode, inBuffer, inBufferSize, outBuffer, outBufferSize, &len, &overlapped)) {
170     DWORD err = GetLastError();
171     if(err == ERROR_IO_PENDING) {
172       WaitForSingleObject(overlapped.hEvent, INFINITE);
173       if(!GetOverlappedResult(handle_, &overlapped, &len, FALSE))
174         return GetLastError();
175     }
176     else
177       return GetLastError();
178   }
179   return ERROR_SUCCESS;
180 }
181
182
183 TunDevice::~TunDevice()
184 {
185   if(handle_ != INVALID_HANDLE_VALUE)
186     CloseHandle(handle_);
187   if(roverlapped_.hEvent != INVALID_HANDLE_VALUE)
188     CloseHandle(roverlapped_.hEvent);
189   if(woverlapped_.hEvent != INVALID_HANDLE_VALUE)
190     CloseHandle(woverlapped_.hEvent);
191 }
192
193 int TunDevice::fix_return(int ret, size_t pi_length) const
194 {
195 // nothing to be done here
196         return 0;
197 }
198
199 int TunDevice::read(u_int8_t* buf, u_int32_t len)
200 {
201   DWORD lenout;
202   roverlapped_.Offset = 0;
203         roverlapped_.OffsetHigh = 0;
204   ResetEvent(roverlapped_.hEvent);
205   
206   if(!ReadFile(handle_, buf, len, &lenout, &roverlapped_)) {
207     DWORD err = GetLastError();
208     if(err == ERROR_IO_PENDING) {
209       WaitForSingleObject(roverlapped_.hEvent, INFINITE);
210       if(!GetOverlappedResult(handle_, &roverlapped_, &lenout, FALSE)) {
211         cLog.msg(Log::PRIO_ERROR) << "Error while trying to get overlapped result: " << AnytunErrno(GetLastError());
212         return -1;
213       }
214     }
215     else {
216       cLog.msg(Log::PRIO_ERROR) << "Error while reading from device: " << AnytunErrno(GetLastError());
217       return -1;
218     }
219   }
220   return lenout;
221 }
222
223 int TunDevice::write(u_int8_t* buf, u_int32_t len)
224 {
225   DWORD lenout;
226   woverlapped_.Offset = 0;
227         woverlapped_.OffsetHigh = 0;
228   ResetEvent(woverlapped_.hEvent);
229
230         if(!WriteFile(handle_, buf, len, &lenout, &woverlapped_)) {
231     DWORD err = GetLastError();
232     if(err == ERROR_IO_PENDING) {
233       WaitForSingleObject(woverlapped_.hEvent, INFINITE);
234       if(!GetOverlappedResult(handle_, &woverlapped_, &lenout, FALSE)) {
235         cLog.msg(Log::PRIO_ERROR) << "Error while trying to get overlapped result: " << AnytunErrno(GetLastError());
236         return -1;
237       }
238     }
239     else {
240       cLog.msg(Log::PRIO_ERROR) << "Error while writing to device: " << AnytunErrno(GetLastError());
241       return -1;
242     }
243   }
244   return lenout;        
245 }
246
247 void TunDevice::init_post()
248 {
249 // nothing to be done here
250 }
251
252 void TunDevice::do_ifconfig()
253 {
254   u_long ep[4];
255   ep[0] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong());
256   ep[1] = htonl(conf_.netmask_.getNetworkAddressV4().to_ulong());
257   ep[2] = htonl(conf_.addr_.getNetworkAddressV4().to_ulong() & conf_.netmask_.getNetworkAddressV4().to_ulong());
258   ep[3] = 365 * 24 * 3600;  // lease time in seconds
259   DWORD err = performIoControl(TAP_IOCTL_CONFIG_DHCP_MASQ, ep, sizeof(ep), ep, sizeof(ep));
260   if(err != ERROR_SUCCESS) {
261     CloseHandle(handle_);
262     AnytunError::throwErr() << "Unable to set device dhcp masq mode: " << AnytunErrno(err);
263         }
264
265   u_long mtu;
266   err = performIoControl(TAP_IOCTL_GET_MTU, &mtu, sizeof(mtu), &mtu, sizeof(mtu));
267   if(err != ERROR_SUCCESS) {
268     CloseHandle(handle_);
269     AnytunError::throwErr() << "Unable to get device mtu: " << AnytunErrno(err);
270         }
271   conf_.mtu_ = static_cast<u_int16_t>(mtu);
272 }
273
274 void TunDevice::waitUntilReady()
275 {
276 // nothing to be done here
277 }