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, &ltime) != 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