1 /*
2 * tun-win32.c
3 *
4 * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5 *
6 * $Id: tun-win32.c,v 1.1 2002/02/25 06:21:59 dugsong Exp $
7 */
8
9 #include "config.h"
10
11 #include <dnet.h>
12 #include <event.h>
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "tun.h"
19
20 #define USER_DEVICE_DIR "\\\\.\\"
21 #define NETCARD_REG_KEY_2000 "SYSTEM\\CurrentControlSet\\Control\\Class" \
22 "\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
23 #if 0
24 #define NETCARD_REG_KEY "SOFTWARE\\Microsoft\\Windows NT" \
25 "\\CurrentVersion\\NetworkCards"
26 #endif
27
28 struct tun {
29 arp_t *arp;
30 intf_t *intf;
31 route_t *route;
32
33 struct arp_entry arpent;
34 struct intf_entry ifent;
35 struct route_entry rtent;
36
37 struct addr dst;
38 HANDLE handle;
39 struct event ev;
40 tun_handler callback;
41 void *arg;
42 };
43
44 static int
reg_query_compare(HKEY key,char * name,char * text)45 reg_query_compare(HKEY key, char *name, char *text)
46 {
47 char value[512];
48 u_long size;
49
50 size = sizeof(value);
51
52 if (RegQueryValueEx(key, name, 0, 0, value, &size) != ERROR_SUCCESS)
53 return (-1);
54
55 return (strcmp(text, value));
56 }
57
58 tun_t *
tun_open(struct addr * src,struct addr * dst,int mtu)59 tun_open(struct addr *src, struct addr *dst, int mtu)
60 {
61 HKEY Key, AdapterKey;
62 FILETIME ltime;
63 tun_t *tun;
64 ip_addr_t mask;
65 u_long i, len;
66 char device[64], AdapterId[512], Value[512];
67
68 if ((tun = calloc(1, sizeof(*tun))) == NULL)
69 return (NULL);
70
71 if ((tun->arp = arp_open()) == NULL ||
72 (tun->intf = intf_open()) == NULL ||
73 (tun->route = route_open()) == NULL)
74 return (tun_close(tun));
75
76 tun->ifent.intf_len = sizeof(tun->ifent);
77 strlcpy(tun->ifent.intf_name, "DKW Heavy Industries VPN Adapter.",
78 sizeof(tun->ifent.intf_name));
79
80 if (intf_get(tun->intf, &tun->ifent) < 0 ||
81 tun->ifent.intf_addr.addr_type != ADDR_TYPE_IP)
82 return (tun_close(tun));
83
84 /* Add fake tunnel gateway. */
85 tun->arpent.arp_pa = tun->ifent.intf_addr;
86 addr_btom(tun->ifent.intf_addr.addr_bits, &mask, sizeof(mask));
87 tun->arpent.arp_pa.addr_ip &= mask;
88 tun->arpent.arp_pa.addr_ip |= htonl(1);
89 tun->arpent.arp_pa.addr_bits = IP_ADDR_BITS;
90 addr_aton("0:d:e:a:d:0", &tun->arpent.arp_ha);
91
92 if (arp_add(tun->arp, &tun->arpent) < 0)
93 return (tun_close(tun));
94
95 /* Add route for destination thru tunnel. */
96 tun->rtent.route_dst = *dst;
97 tun->rtent.route_gw = tun->arpent.arp_pa;
98
99 if (route_add(tun->route, &tun->rtent) < 0)
100 return (tun_close(tun));
101
102 tun->dst = *dst;
103 tun->handle = INVALID_HANDLE_VALUE;
104
105 /* Open CIPE device for reading. */
106 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETCARD_REG_KEY_2000,
107 0, KEY_READ, &Key) != ERROR_SUCCESS)
108 return (tun_close(tun));
109
110 for (i = 0; i < 666; i++) {
111 len = sizeof(AdapterId);
112 if (RegEnumKeyEx(Key, i, AdapterId, &len,
113 0, 0, 0, <ime) != ERROR_SUCCESS)
114 break;
115
116 if (RegOpenKeyEx(Key, AdapterId, 0, KEY_READ,
117 &AdapterKey) != ERROR_SUCCESS)
118 break;
119
120 len = sizeof(Value);
121 if (reg_query_compare(AdapterKey,
122 "Manufacturer", "DKWHeavyIndustries") == 0 &&
123 reg_query_compare(AdapterKey,
124 "ProductName", "CIPE") == 0 &&
125 RegQueryValueEx(AdapterKey, "NetCfgInstanceId",
126 0, 0, Value, &len) == ERROR_SUCCESS) {
127
128 snprintf(device, sizeof(device),
129 USER_DEVICE_DIR "%s.tap", Value);
130
131 tun->handle = CreateFile(device, GENERIC_READ,
132 FILE_SHARE_READ, 0, OPEN_EXISTING,
133 FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_SYSTEM, 0);
134
135 RegCloseKey(AdapterKey);
136 break;
137 }
138 RegCloseKey(AdapterKey);
139 }
140 RegCloseKey(Key);
141
142 if (tun->handle == INVALID_HANDLE_VALUE)
143 return (tun_close(tun));
144
145 return (tun);
146 }
147
148 static void
_tun_recv(int fd,short event,void * arg)149 _tun_recv(int fd, short event, void *arg)
150 {
151 struct event_iov *eio = (struct event_iov *)fd;
152 tun_t *tun = (tun_t *)arg;
153 struct ip_hdr *ip;
154
155 ip = (struct ip_hdr *)(eio->buf + ETH_HDR_LEN);
156
157 if (eio->len > ETH_HDR_LEN + IP_HDR_LEN &&
158 ip->ip_dst == tun->dst.addr_ip) {
159 (*tun->callback)(eio->buf + ETH_HDR_LEN,
160 eio->len - ETH_HDR_LEN, tun->arg);
161 }
162 event_add(&tun->ev, NULL);
163 }
164
165 int
tun_register(tun_t * tun,tun_handler callback,void * arg)166 tun_register(tun_t *tun, tun_handler callback, void *arg)
167 {
168 tun->callback = callback;
169 tun->arg = arg;
170
171 event_set(&tun->ev, (int)tun->handle, EV_READ, _tun_recv, tun);
172 event_add(&tun->ev, NULL);
173
174 return (0);
175 }
176
177 tun_t *
tun_close(tun_t * tun)178 tun_close(tun_t *tun)
179 {
180 if (event_initialized(&tun->ev))
181 event_del(&tun->ev);
182 if (tun->handle != INVALID_HANDLE_VALUE)
183 CloseHandle(tun->handle);
184 if (tun->dst.addr_type == ADDR_TYPE_IP) {
185 route_delete(tun->route, &tun->rtent);
186 arp_delete(tun->arp, &tun->arpent);
187 }
188 if (tun->route != NULL)
189 route_close(tun->route);
190 if (tun->arp != NULL)
191 arp_close(tun->arp);
192
193 free(tun);
194
195 return (NULL);
196 }
197