]> TLD Linux GIT Repositories - packages/openvpn.git/blob - openvpn-ipv6_payload.patch
- updated to 2.3.11
[packages/openvpn.git] / openvpn-ipv6_payload.patch
1 diff -durN openvpn-2.2.2.orig/ChangeLog.IPv6 openvpn-2.2.2/ChangeLog.IPv6
2 --- openvpn-2.2.2.orig/ChangeLog.IPv6   1970-01-01 01:00:00.000000000 +0100
3 +++ openvpn-2.2.2/ChangeLog.IPv6        2012-06-01 10:40:28.000000000 +0200
4 @@ -0,0 +1,440 @@
5 +Do 31. Dez 15:32:40 CET 2009 Gert Doering
6 +
7 +  * Basic IPv6 p2mp functionality implemented
8 +
9 +  * new options:
10 +     - server-ipv6
11 +     - ifconfig-ipv6
12 +     - ifconfig-ipv6-pool
13 +     - route-ipv6
14 +     - iroute-ipv6
15 +
16 +  * modules touched:
17 +     - init.c: init & setup IPv6 route list & add/delete IPv6 routes
18 +     - tun.c: add "ifconfig" and "route" handling for IPv6
19 +     - multi.c: IPv6 ifconfig-pool assignments
20 +               put to route-hash table
21 +               push to client
22 +     - pool.c: extend pools to handle IPv4+IPv6, and also return IPv6 address
23 +              IPv6 address saved to file if ifconfig-pool-persist is set
24 +              (but ignored on read due to the way pools work)
25 +     - mroute.c: handle reading src/dst addresses from IPv6 packets
26 +                (so multi.c can check against route-hash table)
27 +                handle printing of IPv6 mroute_addr structure
28 +     - helper.c: implement "server-ipv6" macro (->ifconfig-ipv6, pool, ...)
29 +     - options.c: implement all the new options
30 +                 add helper functions for IPv6 address handling
31 +     - forward.c: tell do_route() about IPv6 routes
32 +     - route.c:   handle IPv6 route lists + route option lists
33 +                 extend add_routes() to do IPv4 + IPv6 route lists
34 +                 extend delete_routes() to do IPv4 + IPv6 route lists
35 +                 implement add_route_ipv6(), delete_route_ipv6() to call
36 +                 system-dependend external program to do the work
37 +     - push.c:    handle pushing of "ifconfig-ipv6" option
38 +     - socket.c:  helper function to check & print IPv6 address strings
39 +
40 +  * known issues:
41 +     - operating system support on all but Linux (ifconfig, route)
42 +     - route-ipv6 gateway handling
43 +     - iroute-ipv6 not implemented
44 +     - TAP support: ifconfig, routing (route needs gateway!)
45 +
46 +  * release as patch 20091231-1
47 +
48 +Thu Dec 31 17:02:08 CET 2009
49 +
50 +  * NetBSD port (NetBSD 3.1 on Sparc64)
51 +
52 +  * mroute.c, socket.c: make byte/word access to in6_addr more portable
53 +
54 +  * tun.c: fix IPv6 ifconfig arguments on NetBSD
55 +
56 +    still doesn't work on NetBSD 3.1, "ifconfig tun0 inet6..." errors with
57 +
58 +    ifconfig: SIOCAIFADDR: Address family not supported by protocol family
59 +
60 +    (sys/net/if_tun.c, needs to be revision 1.80 or later, NetBSD PR 32944,
61 +    included in NetBSD 4.0 and up)
62 +
63 +
64 +Fri Jan  1 14:07:15 CET 2010
65 +
66 +  * FreeBSD port (FreeBSD 6.3-p12 on i386)
67 +
68 +  * tun.c: implement IPv6 ifconfig setting for FreeBSD
69 +
70 +  * route.c: fix %s/%s argument to IPv6 route add/delete command for *BSD
71 +
72 +  * TEST SUCCESS: FreeBSD 6.3-p12, server-ipv6, route-ipv6, ccd/iroute-ipv6
73 +
74 +  * multi.c: implement setting and deleting of iroute-ipv6 
75 +             (multi_add_iroutes(), multi_del_iroutes())
76 +  * mroute.c: add mroute_helper_add_iroute6(), mroute_helper_del_iroute6()
77 +  * mroute.h: add prototypes, increase MR_HELPER_NET_LEN to 129 (/0.../128)
78 +  * multi.c: zeroize host part of IPv6 iroutes in multi_learn_in6_addr()
79 +  * mroute.c: implement mroute_addr_mask_host_bits() for IPv6
80 +
81 +  * TEST SUCCESS: Linux 2.6.30 (Gentoo)/iproute2, server-ipv6, ccd/iroute-ipv6
82 +
83 +  * TEST SUCCESS: Linux 2.6.30 (Gentoo)/ifconfig, client-ipv6
84 +
85 +  * TEST FAIL: NetBSD 5.0, IPv6 client
86 +     - "ifconfig tun0 .../64" does not create a "connected" route
87 +     - adding routes fails
88 +
89 +     --> more work to do here.
90 +
91 +  * release as patch 20100101-1
92 +
93 +  * TEST FAIL: 
94 +      FreeBSD 6.3-p12 server "--topology subnet"
95 +      Linux/ifconfig client
96 +    - BSD sends ICMP6 neighbor solicitations, which are ignored by Linux
97 +    - server tun interface is not in p2p mode, client tun interface *is*
98 +
99 +  * TEST SUCCESS: non-ipv6 enabled client -> "--server-ipv6" server
100 +    (warnings in the log file, but no malfunctions)
101 +
102 +
103 +Sat Jan  2 19:48:35 CET 2010
104 +
105 +  * tun.c: change "ipv6_support()", do not turn off tt->ipv6 unconditionally
106 +    if we don't know about OS IPv6 support - just log warning
107 +
108 +  * tun.c: implement "ifconfig inet6" setting for MacOS X / Darwin
109 +
110 +  * route.c: split *BSD system dependent part of add/delete_route_ipv6() 
111 +             into FreeBSD/Dragonfly and NetBSD/Darwin/OpenBSD variants 
112 +             ("2001:db8::/64" vs. "2001:db8:: --prefixlen 64").
113 +
114 +  * tun.c: on MacOS X, NetBSD and OpenBSD, explicitely set on-link route
115 +
116 +  * TEST SUCCESS: MacOS X, client-ipv6 with route-ipv6
117 +
118 +
119 +Sun Jan  3 10:55:31 CET 2010
120 +
121 +  * route.c: NetBSD fails with "-iface tun0", needs gateway address
122 +    (assume that the same syntax is needed for OpenBSD)
123 +
124 +  * route.h: introduce "remote_endpoint_ipv6" into "struct route_ipv6_list"
125 +
126 +  * init.c: pass "ifconfig_ipv6_remote" as gateway to init_route_ipv6_list()
127 +
128 +  * route.c: 
129 +    - init_route_ipv6(): use "remote_endpoint_ipv6" as IPv6 gateway address
130 +                         if no gateway was specified explicitely
131 +
132 +    - init_route_ipv6_list(): fill in "remote_endpoint_ipv6", if parseable
133 +
134 +    - get rid of "GATEWAY-LESS ROUTE6" warning
135 +
136 +  * route.c, add_route_ipv6()
137 +    - explicitely clear host bits of base address, to be able to more 
138 +      easily set up "connected" /64 routes on NetBSD+Darwin
139 +
140 +    - split system-dependent part between Darwin and NetBSD/OpenBSD
141 +      (Darwin can use "-iface tun0", NetBSD/OpenBSD get gateway address)
142 +
143 +    - change Solaris comments from "known-broken" to "unknown"
144 +
145 +  * tun.c: rework NetBSD tunnel initialization and tun_read() / tun_write()
146 +    to work the same way OpenBSD and NetBSD do - tunnel is put into 
147 +    "multi-af" mode, and all packet read/write activity is prepended by 
148 +    a 32 bit value specifying the address family.
149 +
150 +  * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6
151 +
152 +  * TEST SUCCESS: MacOS X 10.5: client-ipv6 with route-ipv6
153 +
154 +  * (RE-)TEST SUCCESS: Linux/iproute2: server-ipv6
155 +                       Linux/ifconfig: client-ipv6
156 +                       FreeBSD 6.3: server-ipv6
157 +
158 +  * release as patch 20100103-1
159 +
160 +  * options.c: document all new options in "--help"
161 +
162 +  * tun.c: fix typo in Solaris-specific section
163 +
164 +  * socket.h, socket.c: change u_int32_t to uint32_t 
165 +    (Solaris - and all the rest of the code uses "uintNN" anyway)
166 +
167 +Mon Jan  4 17:46:58 CET 2010
168 +
169 +  * socket.c: rework add_in6_addr() to use 32-bit access to struct in6_addr
170 +    (Solaris has no 16-bit values in union, but this is more elegant as well)
171 +
172 +  * tun.c: fix "ifconfig inet6" command for Solaris
173 +
174 +  * tun.c: make sure "tun0 inet6" is unplumbed first, cleanup leftovers
175 +
176 +  * route.c: add routes with "metric 0" on solaris, otherwise they just
177 +    don't work (someone who understands Solaris might want to fix this).
178 +
179 +  * Solaris "sort of" works now - ifconfig works, route add does not give
180 +    errors, "netstat -rn" looks right, but packets are discarded unless
181 +    the routes are installed with "metric 0".  So we just use "metric 0"...
182 +
183 +  * CAVEAT: Solaris "ifconfig ... preferred" interferes with source address
184 +    selection.  So if there are any active IPv6 interfaces configured with 
185 +    "preferred", packets leaving out the tunnel will use the wrong source
186 +    IPv6 address.  Not fixable from within OpenVPN.
187 +
188 +  * CAVEAT2: Solaris insists on doing DHCPv6 on tun0 interfaces by default,
189 +    so DHCPv6 solicitation packets will be seen.  Since the server end has
190 +    no idea what to do with them, they are a harmless nuisance.  Fixable
191 +    on the Solaris side via "ndpd.conf" (see ``man ifconfig'').
192 +
193 +  * release as patch 20100104-1
194 +
195 +Fri Jan  8 10:00:50 CET 2010
196 +
197 +  * import into git repository
198 +
199 +  * options.c: add sanity checks for most typical error cases
200 +    (--ifconfig-ipv6-pool configured with no --ifconfig-ipv6, etc)
201 +
202 +  * options.c: modify get_ipv6_addr() to be more flexible about netbits
203 +    (optional now, default to /64) and to return the address-without-netbits
204 +    string now (-> for options that want the IPv6 address in printable
205 +    form, but without /nn)
206 +
207 +  * options.c: modify --ifconfig-ipv6 to optionally accept /netbits,
208 +    you can do now "ifconfig-ipv6 2001:df8::1/64 2001:df8::2" or just
209 +    "ifconfig-ipv6 2001:df8::5 2001:df8::7", defaulting to /64
210 +
211 +  * options.h: add necessary structure elements for --ifconfig-ipv6-push
212 +
213 +  * options.c: implement "parse options" side of --ifconfig-ipv6-push
214 +
215 +Tue Jan 12 22:42:09 CET 2010
216 +
217 +  * tun.c: in TARGET_NETBSD #ifdef, distinguish between "old" code
218 +    (IPv4 only, but unmodified read/write) and "new" code (multi-af, 
219 +    extra 32 bit AF on read/write of the tun interface) - pre-4.0
220 +    NetBSD systems don't have TUNSIFHEAD, no way to have common code.
221 +
222 +  * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6 (v4+v6)
223 +
224 +  * TEST SUCCESS: NetBSD 3.1/Sparc64: client-ipv6 with route-ipv6 (v4-only)
225 +
226 +Thu Jan 14 15:41:50 CET 2010
227 +
228 +  * multi.c: if "--ifconfig-push" is used together with "--ifconfig-ipv6-pool"
229 +    and no "--ifconfig-ipv6-push" is seen, issue warning - the current
230 +    implementation of pools has IPv6 tied to IPv4, so if v4 does not use
231 +    the pool, it breaks for IPv6.  Not a *big* problem (since there is 
232 +    enough v6, just give those users a static v6 address as well), but needs
233 +    to be pointed out clearly.
234 +
235 +  * release as patch 20100114-1
236 +
237 +Tue Feb 16 14:43:28 CET 2010
238 +
239 +  * options.c: print "IPv6 payload patch" release date in "--version"
240 +
241 +  * tun.c: undo change to init_tun() (moving "bool tun" and call to
242 +    "is_tun_p2p()" further up) - it wasn't needed and breaks "make check"
243 +
244 +  * git stuff: rebase on David Sommerseth's openvpn-testing git tree
245 +
246 +  * release as patch 20100216-1
247 +
248 +Fri Feb 26 19:59:01 CET 2010
249 +
250 +  * init.c: initialize tuntap->ipv6 in do_init_tun() (to make sure it's
251 +    always initialized early-enough, independent of the sequence of
252 +    do_ifconfig()/open_tun() [see ifconfig_order() in tun.h])
253 +
254 +  * tun.c, init.c: remove "bool ipv6" argument to tuncfg(), open_tun()
255 +    and open_tun_generic() - obsoleted by previous change
256 +
257 +  * tun.c: remove ipv6_support() - original purpose was unclear, and all
258 +    current platforms (except linux-very-old) fully support IPv6 now :-)
259 +
260 +  * tun.c: initial implementation of "netsh" IPv6-ifconfig for Win32
261 +
262 +  * RE-TEST SUCCESS: Linux/i386/ifconfig, client-tun/net30, v4+v6
263 +
264 +Sun Feb 28 17:05:57 CET 2010
265 +
266 +  * tun.c: NetBSD dependent part: correct destroying/re-creation of tun dev
267 +
268 +  * tun.c: move adding of "connected" IPv6 prefix to new helper function,
269 +           add_route_connected_v6_net()
270 +
271 +  * RE-TEST SUCCESS: NetBSD 5.0/Sparc64, client-tun/net30, v4+v6
272 +
273 +  * RE-TEST SUCCESS: NetBSD 3.1/Sparc64: client-tun/net30, v4-only
274 +
275 +  * RE-TEST SUCCESS: Linux/i386/iproute2: server-tun/net30, v4+v6
276 +
277 +  * tun.c: add #ifdef TARGET_DARWIN block for *_tun() functions, to
278 +           be able to modify close_tun() for unconfiguring IPv6
279 +
280 +  * tun.c: on close_tun() on MacOS X, need to de-configure "lo0" route for
281 +           configured IPv6 address
282 +
283 +  * RE-TEST SUCCESS: MacOS X (10.5)/i386: client-tun/net30, v4+v6
284 +
285 +  * route.c: implement ipv6 route adding / deletion via "netsh" for WIN32
286 +
287 +  * TEST FAIL: Windows XP fails, because the tun/tap driver does not
288 +    forward IPv6 frames kernel->userland if in "tun" mode
289 +
290 +  * options.c: set IPv6 version to 20100228-1
291 +
292 +  * release as patch 20100228-1
293 +
294 +Sun Mar  7 19:17:33 CET 2010
295 +
296 +  * options.c: set IPv6 version to 20100307-1
297 +
298 +  * TODO.IPv6: add note about OpenBSD TODO (#16)
299 +
300 +  * route.c: set (and remove) "magic next hop" fe80::8 for IPv6 routes on
301 +    Win32
302 +
303 +  * install-win32/settings.in: bump TAP driver version from 9.6 to 9.7
304 +    and TAP_RELDATE to "07/03/2010"
305 +
306 +  * tap-win32/proto.h: add data types and definitions needed for IPv6
307 +
308 +  * tap-win32/types.h: add m_UserToTap_IPv6 ethernet header for IPv6 packets
309 +
310 +  * tap-win32/tapdrvr.c: implement support for IPv6 in TUN mode:
311 +     - IPv6 packets User->OS need correct ether type
312 +     - IPv6 packets OS->User get correctly forwarded
313 +     - IPv6 neighbour discovery packets for "fe80::8" (magic address
314 +       installed as route-nexthop by OpenVPN.exe) get answered locally
315 +
316 +  * TEST SUCCESS: WindowsXP/32bit: client-tun/net30, v4+v6
317 +
318 +  * tun.c: if IPv6 requested in TUN mode, and TUN/TAP driver version
319 +    is older than 9.7, log warning and disable IPv6 (won't work anyway).
320 +
321 +  * release as patch 20100307-1
322 +
323 +Sat Jul 10 14:37:52 CEST 2010
324 +
325 +  * TEST SUCCESS: point-to-point tun mode with --ifconfig-ipv6 between
326 +                  Solaris10/sparc and Linux (Michal Ludvig)
327 +    (using the whiteboard tun driver on Solaris, otherwise "no IPv6")
328 +
329 +Sun Aug  8 12:30:44 CEST 2010
330 +
331 +  * route.c: split NetBSD and OpenBSD parts of add_route_ipv6() and
332 +             delete_route_ipv6(), implement OpenBSD variant
333 +             (needs "-prefixlen nn" while NetBSD uses "/nn")
334 +
335 +  * tun.c: implement IPv6 ifconfig for OpenBSD
336 +
337 +  * tun.c: destroy tunX interface at tun_close() on OpenBSD (cleanup)
338 +
339 +  * TEST SUCCESS: OpenBSD 4.7: client-tun/net30, v4+v6
340 +
341 +Thu Sep  2 21:18:32 CEST 2010
342 +
343 +  * tun.c: the TAP binary in 2.2-beta3 has the IPv6 related changes, but
344 +    the version number is 9.8 now -> check for 9.8, not 9.7
345 +
346 +Wed Sep 22 22:20:37 CEST 2010
347 +
348 +  * tun.c: bugfix for Linux/iproute2/"topology subnet".  Works :-)
349 +
350 +  * TEST SUCCESS: Linux/ifconfig: client-tun/net30+subnet, v4+v6
351 +
352 +  * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6
353 +
354 +  * options.c: tag as 20100922-1 so "allmerged" users can see IPv6 change
355 +
356 +Fri Sep 24 17:57:41 CEST 2010
357 +
358 +  * TEST SUCCESS: Linux/<both>: client-tap, v4+v6, ping6 on connected addr
359 +
360 +  * TEST FAIL: Linux/<both>: client-tap, v6, route6 (gateway missing)
361 +
362 +Do 21. Okt 19:36:49 CEST 2010
363 +
364 +  * t_client.sh.in: cherrypick commit f25fe91a40aa3f and 6f1e61b41be52 
365 +    (proper exit codes to signal "SKIP" if we do not want to run)
366 +
367 +So 16. Jan 17:25:23 CET 2011
368 +
369 +  * tun.c, route.c: cherrypick 121755c2cb4891f and f0eac1a5979096c67
370 +    (TAP driver and "topology subnet" support for Solaris)
371 +
372 +  * tun.c: add IPv6 configuration for TAP interfaces (<device>:1 inet6)
373 +
374 +  * tun.c: on close_tun on Solaris, unplumb IPv6 TUN or TAP interfaces
375 +
376 +  * TEST SUCCESS: OpenSolaris: client-tun, v4+v6
377 +    TEST SUCCESS: OpenSolaris: client-tap, v4+v6, ping6 on connected addr
378 +    TEST FAIL: OpenSolaris: client-tap, v6, route6 (gateway missing)
379 +
380 +So 24. Apr 16:51:45 CEST 2011
381 +
382 +  * rebase to "beta2.2" branch (at 2.2RC2 tag)
383 +
384 +  * mroute.c: remove mroute_helper_lock/_unlock() calls for IPv6
385 +  * socket.c: remove locking with L_INET_NTOA mutex
386 +      (all the threading stuff got removed by David Sommerseth for 2.2)
387 +
388 +  * mroute.c: remove duplicate mroute_helper_add_iroute6() and
389 +              mroute_helper_del_iroute6() - "git rebase" artefact
390 +
391 +  * ChangeLog.IPv6 and TODO.IPv6: add to commit
392 +
393 +  * options.c: tag as 20110424-2 (2.2RC2)
394 +
395 +  * TEST SUCCESS: Linux/ifconfig: client-tun/net30+subnet, v4+v6
396 +
397 +  * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6
398 +
399 +Thu Apr 28 19:10:01 CEST 2011
400 +
401 +  * rebase to "origin/release/2.2" branch (at v2.2.0 tag)
402 +
403 +Thu May 19 20:51:12 CEST 2011
404 +
405 +  * include Windows "netsh add" -> "netsh set ... store=active" patch from
406 +    Seth Mos, to fix restart problems on Windows due to persistant addresses
407 +
408 +  * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6
409 +
410 +Sat May 21 17:03:20 CEST 2011
411 +
412 +  * tun.c: Solaris cleanup (use CLEAR() to zero-out "ifr")
413 +
414 +  * tun.c: Windows cleanup: remove route and IPv6 address on disconnect
415 +
416 +  * route.c, route.h: remove "static" from delete_route_ipv6(), needed
417 +    for ipv6-route cleanup on disconnect
418 +
419 +  * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6
420 +
421 +  * TEST SUCCESS: Windows 7 Home Premium: client-tun/net30, v4+v6
422 +
423 +So 22. Mai 14:46:12 CEST 2011
424 +
425 +  * Tony Lim: removing routes fails on windows if certain bits are set
426 +    in the "host part" (others are silently ignored) -->
427 +
428 +  * route.c: create print_in6_addr_netbits_only() helper, call from 
429 +    add_route_ipv6() and delete_route_ipv6() to get only network part
430 +    of route-to-be-modified
431 +
432 +  * route.c: set 'store=active' on adding routes on WIN32 as well (Tony Lim)
433 +
434 +  * options.c: bump IPv6 release to 20110522-1
435 +
436 +  * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6
437 +
438 +  * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6
439 +
440 +  * TEST SUCCESS: Windows 7 Home Premium: client-tun/net30, v4+v6
441 +
442 +  * TEST SUCCESS: OpenBSD 4.7: client-tun/net30, v4+v6
443 +    TEST FAIL: OpenBSD 4.7: client-tun/subnet, v4
444 +    (seems to be due to "topology subnet has just not been implemented yet")
445 diff -durN openvpn-2.2.2.orig/README.IPv6 openvpn-2.2.2/README.IPv6
446 --- openvpn-2.2.2.orig/README.IPv6      1970-01-01 01:00:00.000000000 +0100
447 +++ openvpn-2.2.2/README.IPv6   2012-06-01 10:40:28.000000000 +0200
448 @@ -0,0 +1,8 @@
449 +This is an experimentally patched version of OpenVPN 2.1 with IPv6
450 +payload support.
451 +
452 +Go here for release notes and documentation:
453 +
454 +  http://www.greenie.net/ipv6/openvpn.html
455 +
456 +Gert Doering, 31.12.2009
457 diff -durN openvpn-2.2.2.orig/TODO.IPv6 openvpn-2.2.2/TODO.IPv6
458 --- openvpn-2.2.2.orig/TODO.IPv6        1970-01-01 01:00:00.000000000 +0100
459 +++ openvpn-2.2.2/TODO.IPv6     2012-06-01 10:40:28.000000000 +0200
460 @@ -0,0 +1,153 @@
461 +known issues for IPv6 payload support in OpenVPN
462 +-----------------------------------------------
463 +
464 +1.) "--topology subnet" doesn't work together with IPv6 payload on FreeBSD
465 +    (verified for FreeBSD server, Linux/ifconfig client, problems 
466 +    with ICMP6 neighbor solicitations from BSD not being answered by Linux)
467 +
468 +2.) NetBSD IPv6 support doesn't work
469 +    ("connected" route is not auto-created, "route-ipv6" adding fails)
470 +
471 +    * fixed, 3.1.10 *
472 +
473 +3.) route deletion for IPv6 routes is not yet done
474 +
475 +    * fixed for configured routes, 3.1.10 *
476 +    * missing for manual-ifconfig-connected (NetBSD, Darwin, Win32)
477 +      * fixed for Win32, 22.5.2011
478 +
479 +4.) do "ifconfig tun0 inet6 unplumb"  or "ifconfig tun0 destroy" for
480 +    Solaris, *BSD, ... at program termination time, to clean up leftovers
481 +    (unless tunnel persistance is desired).
482 +
483 +    For Solaris, only the "ipv6 tun0" is affected, for the *BSDs all tun0
484 +    stay around.
485 +
486 +4a.) deconfigure IPv6 on tun interface on session termination, otherwise
487 +    one could end up with something like this (on NetBSD):
488 +
489 +tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
490 +        inet 10.9.0.18 -> 10.9.0.17 netmask 0xffffffff
491 +        inet6 fe80::a00:20ff:fece:d299%tun0 ->  prefixlen 64 scopeid 0x3
492 +        inet6 2001:608:4:eff::2000:3 ->  prefixlen 64
493 +        inet6 2001:608:4:eff::1:3 ->  prefixlen 64
494 +
495 +    (pool was changed, previous address still active on tun0, breakage)
496 +
497 +    * semi-fixed for NetBSD, 28.2.10, always do tun0 destroy / tun0 create
498 +      before actual ifconfig -- tunnel still lingers after OpenVPN quits
499 +
500 +4b.) verify this - on FreeBSD, tun0 is auto-destroyed if created by
501 +     opening /dev/tun (and lingers if created by "ifconfig tun0 create")
502 +
503 +     -> use for persistant tunnels on not-linux?
504 +
505 +5.) add new option "ifconfig-ipv6-push"
506 +    (per-client static IPv6 assignment, -> radiusplugin, etc)
507 +
508 +    * implemented, 14.1.10 *
509 +
510 +6.) add new option "route-ipv6-gateway"
511 +
512 +7.) add "full" gateway handling for IPv6 in route.c 
513 +    (right now, the routes are just sent down the tun interface, if the
514 +    operating system in questions supports that, without care for the
515 +    gateway address - which does not work for gateways that are supposed
516 +    to point elsewhere.  Also, it doesn't work for TAP interfaces.
517 +
518 +8.) full IPv6 support for TAP interfaces 
519 +    (main issue should be routes+gateway - and testing :-) )
520 +
521 +    test 2010/09/24: TAP itself works on linux/ifconfig+iproute2, but 
522 +    route-via-tap doesn't work at all (route points to "tap0" which fails)
523 +
524 +17:51:14.075412 fe:ab:6e:c5:53:71 > 33:33:ff:00:00:01, ethertype IPv6 (0x86dd), length 86: 2001:608:4:a053::1:0 > ff02::1:ff00:1: ICMP6, neighbor solicitation, who has 2001:608:4:a001::1, length 32
525 +
526 +    how is iroute-via-tap supposed to work??
527 +
528 +9.) verify that iroute-ipv6 and route-ipv6 interact in the same way as
529 +    documented for iroute/route:
530 +
531 +    A's subnet, OpenVPN must push this route to all clients
532 +    EXCEPT for A, since the subnet is already owned by A.
533 +    OpenVPN accomplishes this by not
534 +    not pushing a route to a client
535 +    if it matches one of the client's iroutes.
536 +
537 +10.) extend "ifconfig-ipv6" to handle specification of /netbits, pushing
538 +    of /netbits, and correctly ifconfig'ing this
539 +    (default, if not specified: /64)
540 +
541 +11.) do not add ipv6-routes if tun-ipv6 is not set - complain instead
542 +
543 +     * done * 12.1.10
544 +
545 +12.) handle incoming [::] and [fe80:...] packets in tun-p2mp MULTI mode
546 +     (most likely those are DAD packets)
547 +     silently ignore DAD?  
548 +        Or accept-and-forward iff (multicast && client2client)?
549 +     handle NS/NA
550 +
551 +13.) from Martin List-Petersen:
552 +
553 +       One thing, and I guess this requires modifications in
554 +       network-manager-openvpn: It also works, BUT ignores "push
555 +       route-ipv6-gateway" and "push route-ipv6 ...." (obviously routes pushed
556 +       from the server) entirely.
557 +
558 +14.) from ##openvpn-discussion:
559 +
560 +       new features should be #ifdef'ed
561 +
562 +       (check whether this is feasible at all)
563 +
564 +15.) IPv6 related environment variables
565 +
566 +       - document all of them in openvpn.8
567 +       - make sure that all existing IPv4 stuff has IPv6 counterparts
568 +
569 +16.) OpenBSD
570 +       - implement ifconfig/route for IPv6
571 +       - revert ifconfig/open_tun order to "normal" (separate commit!!!)
572 +         (openvpn-devel, Subject: OpenBSD)
573 +       - test
574 +
575 +17.) client-option (Elwood)
576 +       - ignore-v6-push-options yes/no
577 +       - ignore-v6-route-push  ("as for IPv4 routes")
578 +
579 +18.) fail-save?  "what if 'ip -6 addr add' fails" -> fail, or fallback to v4?
580 +       (-> recomment setting "ignore-v6-push-options yes")
581 +
582 +19.) safety check: if connecting over IPv6 (v6 transport) and the pushed
583 +     route-ipv6 network encompasses the server IPv6 address, make sure 
584 +     we at least log a warning (until we can fiddle with external routing
585 +     to make this work correctly).
586 +
587 +20.) show "route add" / "route delete" commands for IPv6 in log file
588 +     (we show the "ifconfig" commands, so why not the routes?)
589 +
590 +     2010-08-07: this is a null-feature - it's already there, but with
591 +                 different debug level (M_INFO vs. D_ROUTE) so user 
592 +                 didn't notice
593 +
594 +21.) enable ipv6-only server operations
595 +      - decouple ipv6 pool handling from ipv4 pool
596 +      - make sure Rest of OpenVPN doesn't assume "there will always be IPv4"
597 +
598 +22.) implement --learn-address for IPv6
599 +
600 +23.) FreeBSD 8 seems to require explicit setting of the "ifconfig" IPv6
601 +     route, while FreeBSD 6+7 don't --> more testing, and code fix
602 +
603 +     workaround for the time being: just add
604 +
605 +       server-ipv6 2001:608:4:a051::/64
606 +       route-ipv6 2001:608:4:a051::/64
607 +
608 +    to the config
609 +
610 +    (problem + workaround applies both to tun and tap style devices)
611 +
612 +24.) implement link-local IPv6 addresses
613 +     (OSPFv3 over TUN/multipoint does not work right now)
614 diff -durN openvpn-2.2.2.orig/forward.c openvpn-2.2.2/forward.c
615 --- openvpn-2.2.2.orig/forward.c        2011-12-13 17:58:56.000000000 +0100
616 +++ openvpn-2.2.2/forward.c     2012-06-01 10:40:28.000000000 +0200
617 @@ -262,7 +262,8 @@
618  static void
619  check_add_routes_action (struct context *c, const bool errors)
620  {
621 -  do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
622 +  do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
623 +           c->c1.tuntap, c->plugins, c->c2.es);
624    update_time ();
625    event_timeout_clear (&c->c2.route_wakeup);
626    event_timeout_clear (&c->c2.route_wakeup_expire);
627 diff -durN openvpn-2.2.2.orig/helper.c openvpn-2.2.2/helper.c
628 --- openvpn-2.2.2.orig/helper.c 2011-12-13 17:58:56.000000000 +0100
629 +++ openvpn-2.2.2/helper.c      2012-06-01 10:40:28.000000000 +0200
630 @@ -142,6 +142,55 @@
631  
632  #if P2MP
633  #if P2MP_SERVER
634 +
635 +  /* 
636 +   *
637 +   * HELPER DIRECTIVE for IPv6
638 +   *
639 +   * server-ipv6 2001:db8::/64
640 +   *
641 +   * EXPANDS TO:
642 +   *
643 +   * tun-ipv6
644 +   * push "tun-ipv6"
645 +   * ifconfig-ipv6 2001:db8::1 2001:db8::2
646 +   * if !nopool: 
647 +   *   ifconfig-ipv6-pool 2001:db8::1:0/64
648 +   * 
649 +   */
650 +   if ( o->server_ipv6_defined )
651 +     {
652 +       if ( ! o->server_defined )
653 +         {
654 +           msg (M_USAGE, "--server-ipv6 must be used together with --server");
655 +         }
656 +       if ( o->server_flags & SF_NOPOOL )
657 +         {
658 +           msg( M_USAGE, "--server-ipv6 is incompatible with 'nopool' option" );
659 +         }
660 +       if ( o->ifconfig_ipv6_pool_defined )
661 +         {
662 +           msg( M_USAGE, "--server-ipv6 already defines an ifconfig-ipv6-pool, so you can't also specify --ifconfig-pool explicitly");
663 +         }
664 +
665 +        /* local ifconfig is "base address + 1" and "+2" */
666 +       o->ifconfig_ipv6_local = 
667 +               print_in6_addr( add_in6_addr( o->server_network_ipv6, 1), 0, &o->gc );
668 +       o->ifconfig_ipv6_remote = 
669 +               print_in6_addr( add_in6_addr( o->server_network_ipv6, 2), 0, &o->gc );
670 +
671 +       /* pool starts at "base address + 0x10000" */
672 +       ASSERT( o->server_netbits_ipv6 < 96 );          /* want 32 bits */
673 +       o->ifconfig_ipv6_pool_defined = true;
674 +       o->ifconfig_ipv6_pool_base = 
675 +               add_in6_addr( o->server_network_ipv6, 0x10000 );
676 +       o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6;
677 +
678 +       o->tun_ipv6 = true;
679 +
680 +       push_option( o, "tun-ipv6", M_USAGE );
681 +     }
682 +
683    /*
684     *
685     * HELPER DIRECTIVE:
686 diff -durN openvpn-2.2.2.orig/init.c openvpn-2.2.2/init.c
687 --- openvpn-2.2.2.orig/init.c   2011-12-13 17:58:56.000000000 +0100
688 +++ openvpn-2.2.2/init.c        2012-06-01 10:40:28.000000000 +0200
689 @@ -843,7 +843,7 @@
690         msg (M_FATAL|M_OPTERR,
691              "options --mktun or --rmtun should only be used together with --dev");
692        tuncfg (options->dev, options->dev_type, options->dev_node,
693 -             options->tun_ipv6, options->persist_mode,
694 +             options->persist_mode,
695               options->username, options->groupname, &options->tuntap_options);
696        if (options->persist_mode && options->lladdr)
697          set_lladdr(options->dev, options->lladdr, NULL);
698 @@ -1066,6 +1066,8 @@
699  {
700    if (c->options.routes && !c->c1.route_list)
701      c->c1.route_list = new_route_list (c->options.max_routes, &c->gc);
702 +  if (c->options.routes_ipv6 && !c->c1.route_ipv6_list)
703 +    c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc);
704  }
705  
706  
707 @@ -1108,6 +1110,45 @@
708      }
709  }
710  
711 +static void
712 +do_init_route_ipv6_list (const struct options *options,
713 +                   struct route_ipv6_list *route_ipv6_list,
714 +                   bool fatal,
715 +                   struct env_set *es)
716 +{
717 +  const char *gw = NULL;
718 +  int dev = dev_type_enum (options->dev, options->dev_type);
719 +  int metric = 0;
720 +
721 +  if (dev != DEV_TYPE_TUN )
722 +    msg( M_WARN, "IPv6 routes on TAP devices are going to fail on some platforms (need gateway spec)" );       /* TODO-GERT */
723 +
724 +  gw = options->ifconfig_ipv6_remote;          /* default GW = remote end */
725 +#if 0                                  /* not yet done for IPv6 - TODO!*/
726 +  if ( options->route_ipv6_default_gateway )           /* override? */
727 +    gw = options->route_ipv6_default_gateway;
728 +#endif
729 +
730 +  if (options->route_default_metric)
731 +    metric = options->route_default_metric;
732 +
733 +  if (!init_route_ipv6_list (route_ipv6_list,
734 +                       options->routes_ipv6,
735 +                       gw,
736 +                       metric,
737 +                       es))
738 +    {
739 +      if (fatal)
740 +       openvpn_exit (OPENVPN_EXIT_STATUS_ERROR);       /* exit point */
741 +    }
742 +  else
743 +    {
744 +      /* copy routes to environment */
745 +      setenv_routes_ipv6 (es, route_ipv6_list);
746 +    }
747 +}
748 +
749 +
750  /*
751   * Called after all initialization has been completed.
752   */
753 @@ -1172,12 +1213,13 @@
754  void
755  do_route (const struct options *options,
756           struct route_list *route_list,
757 +         struct route_ipv6_list *route_ipv6_list,
758           const struct tuntap *tt,
759           const struct plugin_list *plugins,
760           struct env_set *es)
761  {
762 -  if (!options->route_noexec && route_list)
763 -    add_routes (route_list, tt, ROUTE_OPTION_FLAGS (options), es);
764 +  if (!options->route_noexec && ( route_list || route_ipv6_list ) )
765 +    add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es);
766  
767    if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP))
768      {
769 @@ -1234,11 +1276,16 @@
770                            c->options.topology,
771                            c->options.ifconfig_local,
772                            c->options.ifconfig_remote_netmask,
773 +                          c->options.ifconfig_ipv6_local,
774 +                          c->options.ifconfig_ipv6_remote,
775                            addr_host (&c->c1.link_socket_addr.local),
776                            addr_host (&c->c1.link_socket_addr.remote),
777                            !c->options.ifconfig_nowarn,
778                            c->c2.es);
779  
780 +  /* flag tunnel for IPv6 config if --tun-ipv6 is set */
781 +  c->c1.tuntap->ipv6 = c->options.tun_ipv6;
782 +
783    init_tun_post (c->c1.tuntap,
784                  &c->c2.frame,
785                  &c->options.tuntap_options);
786 @@ -1270,6 +1317,8 @@
787        /* parse and resolve the route option list */
788        if (c->options.routes && c->c1.route_list && c->c2.link_socket)
789         do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es);
790 +      if (c->options.routes_ipv6 && c->c1.route_ipv6_list )
791 +       do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es);
792  
793        /* do ifconfig */
794        if (!c->options.ifconfig_noexec
795 @@ -1286,7 +1335,7 @@
796  
797        /* open the tun device */
798        open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
799 -               c->options.tun_ipv6, c->c1.tuntap);
800 +               c->c1.tuntap);
801  
802        /* set the hardware address */
803        if (c->options.lladdr)
804 @@ -1315,7 +1364,8 @@
805  
806        /* possibly add routes */
807        if (!c->options.route_delay_defined)
808 -       do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
809 +       do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
810 +                 c->c1.tuntap, c->plugins, c->c2.es);
811  
812        /*
813         * Did tun/tap driver give us an MTU?
814 @@ -1389,8 +1439,9 @@
815  #endif
816  
817           /* delete any routes we added */
818 -         if (c->c1.route_list)
819 -           delete_routes (c->c1.route_list, c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es);
820 +         if (c->c1.route_list || c->c1.route_ipv6_list )
821 +           delete_routes (c->c1.route_list, c->c1.route_ipv6_list,
822 +                          c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es);
823  
824           /* actually close tun/tap device based on --down-pre flag */
825           if (!c->options.down_pre)
826 diff -durN openvpn-2.2.2.orig/init.h openvpn-2.2.2/init.h
827 --- openvpn-2.2.2.orig/init.h   2011-12-13 17:58:56.000000000 +0100
828 +++ openvpn-2.2.2/init.h        2012-06-01 10:40:28.000000000 +0200
829 @@ -63,6 +63,7 @@
830  
831  void do_route (const struct options *options,
832                struct route_list *route_list,
833 +              struct route_ipv6_list *route_ipv6_list,
834                const struct tuntap *tt,
835                const struct plugin_list *plugins,
836                struct env_set *es);
837 diff -durN openvpn-2.2.2.orig/misc.c openvpn-2.2.2/misc.c
838 --- openvpn-2.2.2.orig/misc.c   2011-12-13 17:58:56.000000000 +0100
839 +++ openvpn-2.2.2/misc.c        2012-06-01 10:40:28.000000000 +0200
840 @@ -1001,7 +1001,9 @@
841         {
842           const char *str = construct_name_value (name_tmp, val_tmp, &gc);
843           env_set_add (es, str);
844 -         /*msg (M_INFO, "SETENV_ES '%s'", str);*/
845 +#if DEBUG_VERBOSE_SETENV
846 +         msg (M_INFO, "SETENV_ES '%s'", str);
847 +#endif
848         }
849        else
850         env_set_del (es, name_tmp);
851 diff -durN openvpn-2.2.2.orig/mroute.c openvpn-2.2.2/mroute.c
852 --- openvpn-2.2.2.orig/mroute.c 2011-12-13 21:17:06.000000000 +0100
853 +++ openvpn-2.2.2/mroute.c      2012-06-01 10:42:51.000000000 +0200
854 @@ -88,12 +88,33 @@
855      }
856  }
857  
858 +static inline void
859 +mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
860 +{
861 +  if (ma)
862 +    {
863 +      ma->type = MR_ADDR_IPV6 | mask;
864 +      ma->netbits = 0;
865 +      ma->len = 16;
866 +      *(struct in6_addr *)ma->addr = src;
867 +    }
868 +}
869 +
870  static inline bool
871  mroute_is_mcast (const in_addr_t addr)
872  {
873    return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
874  }
875  
876 +/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies 
877 + *                 the address as being a multicast address"
878 + */
879 +static inline bool
880 +mroute_is_mcast_ipv6 (const struct in6_addr addr)
881 +{
882 +  return (addr.s6_addr[0] == 0xff);
883 +}
884 +
885  #ifdef ENABLE_PF
886  
887  static unsigned int
888 @@ -157,13 +178,29 @@
889             }
890           break;
891         case 6:
892 -         {
893 -            if( !ipv6warned ) {
894 -              msg (M_WARN, "IPv6 in tun mode is not supported in OpenVPN 2.2");
895 -              ipv6warned = true;
896 -            }
897 -           break;
898 -         }
899 +         if (BLEN (buf) >= (int) sizeof (struct openvpn_ipv6hdr))
900 +           {
901 +             const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR (buf);
902 +#if 0                          /* very basic debug */
903 +             struct gc_arena gc = gc_new ();
904 +             msg( M_INFO, "IPv6 packet! src=%s, dst=%s",
905 +                       print_in6_addr( ipv6->saddr, 0, &gc ),
906 +                       print_in6_addr( ipv6->daddr, 0, &gc ));
907 +             gc_free (&gc);
908 +#endif
909 +
910 +             mroute_get_in6_addr (src, ipv6->saddr, 0);
911 +             mroute_get_in6_addr (dest, ipv6->daddr, 0);
912 +
913 +             if (mroute_is_mcast_ipv6 (ipv6->daddr))
914 +               ret |= MROUTE_EXTRACT_MCAST;
915 +
916 +             ret |= MROUTE_EXTRACT_SUCCEEDED;
917 +           }
918 +         break;
919 +       default:
920 +           msg (M_WARN, "IP packet with unknown IP version=%d seen",
921 +                        OPENVPN_IPH_GET_VER (*BPTR(buf)));
922         }
923      }
924    return ret;
925 @@ -257,14 +294,36 @@
926   * Zero off the host bits in an address, leaving
927   * only the network bits, using the netbits member of
928   * struct mroute_addr as the controlling parameter.
929 + *
930 + * TODO: this is called for route-lookup for every yet-unhashed
931 + * destination address, so for lots of active net-iroutes, this
932 + * might benefit from some "zeroize 32 bit at a time" improvements
933   */
934  void
935  mroute_addr_mask_host_bits (struct mroute_addr *ma)
936  {
937    in_addr_t addr = ntohl(*(in_addr_t*)ma->addr);
938 -  ASSERT ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4);
939 -  addr &= netbits_to_netmask (ma->netbits);
940 -  *(in_addr_t*)ma->addr = htonl (addr);
941 +  if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
942 +    {
943 +      addr &= netbits_to_netmask (ma->netbits);
944 +      *(in_addr_t*)ma->addr = htonl (addr);
945 +    }
946 +  else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
947 +    {
948 +      int byte = ma->len-1;            /* rightmost byte in address */
949 +      int bits_to_clear = 128 - ma->netbits;
950 +
951 +      while( byte >= 0 && bits_to_clear > 0 )
952 +        {
953 +         if ( bits_to_clear >= 8 )
954 +           { ma->addr[byte--] = 0; bits_to_clear -= 8; }
955 +         else
956 +           { ma->addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
957 +        }
958 +      ASSERT( bits_to_clear == 0 );
959 +    }
960 +  else
961 +      ASSERT(0);
962  }
963  
964  /*
965 @@ -342,17 +401,24 @@
966           }
967           break;
968         case MR_ADDR_IPV6:
969 -         buf_printf (&out, "IPV6"); 
970 -         break;
971 -       default:
972 -         buf_printf (&out, "UNKNOWN"); 
973 -         break;
974 -       }
975 -      return BSTR (&out);
976 -    }
977 -  else
978 -    return "[NULL]";
979 -}
980 +         {
981 +           buf_printf (&out, "%s",
982 +                 print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc)); 
983 +           if (maddr.type & MR_WITH_NETBITS)
984 +             {
985 +               buf_printf (&out, "/%d", maddr.netbits);
986 +             }
987 +           }
988 +           break;
989 +         default:
990 +           buf_printf (&out, "UNKNOWN"); 
991 +           break;
992 +         }
993 +       return BSTR (&out);
994 +      }
995 +    else
996 +      return "[NULL]";
997 +  }
998  
999  /*
1000   * mroute_helper's main job is keeping track of
1001 @@ -422,6 +488,40 @@
1002         mroute_helper_regenerate (mh);
1003      }
1004  }
1005 +
1006 +/* this is a bit inelegant, we really should have a helper to that 
1007 + * is only passed the netbits value, and not the whole struct iroute *
1008 + * - thus one helper could do IPv4 and IPv6.  For the sake of "not change
1009 + * code unrelated to IPv4" this is left for later cleanup, for now.
1010 + */
1011 +void
1012 +mroute_helper_add_iroute6 (struct mroute_helper *mh, 
1013 +                           const struct iroute_ipv6 *ir6)
1014 +{
1015 +  if (ir6->netbits >= 0)
1016 +    {
1017 +      ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
1018 +      ++mh->cache_generation;
1019 +      ++mh->net_len_refcount[ir6->netbits];
1020 +      if (mh->net_len_refcount[ir6->netbits] == 1)
1021 +       mroute_helper_regenerate (mh);
1022 +    }
1023 +}
1024 +
1025 +void
1026 +mroute_helper_del_iroute6 (struct mroute_helper *mh, 
1027 +                          const struct iroute_ipv6 *ir6)
1028 +{
1029 +  if (ir6->netbits >= 0)
1030 +    {
1031 +      ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
1032 +      ++mh->cache_generation;
1033 +      --mh->net_len_refcount[ir6->netbits];
1034 +      ASSERT (mh->net_len_refcount[ir6->netbits] >= 0);
1035 +      if (!mh->net_len_refcount[ir6->netbits])
1036 +       mroute_helper_regenerate (mh);
1037 +    }
1038 +}
1039  
1040  void
1041  mroute_helper_free (struct mroute_helper *mh)
1042 diff -durN openvpn-2.2.2.orig/mroute.c~ openvpn-2.2.2/mroute.c~
1043 --- openvpn-2.2.2.orig/mroute.c~        1970-01-01 01:00:00.000000000 +0100
1044 +++ openvpn-2.2.2/mroute.c~     2012-06-01 10:40:28.000000000 +0200
1045 @@ -0,0 +1,518 @@
1046 +/*
1047 + *  OpenVPN -- An application to securely tunnel IP networks
1048 + *             over a single TCP/UDP port, with support for SSL/TLS-based
1049 + *             session authentication and key exchange,
1050 + *             packet encryption, packet authentication, and
1051 + *             packet compression.
1052 + *
1053 + *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
1054 + *
1055 + *  This program is free software; you can redistribute it and/or modify
1056 + *  it under the terms of the GNU General Public License version 2
1057 + *  as published by the Free Software Foundation.
1058 + *
1059 + *  This program is distributed in the hope that it will be useful,
1060 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1061 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1062 + *  GNU General Public License for more details.
1063 + *
1064 + *  You should have received a copy of the GNU General Public License
1065 + *  along with this program (see the file COPYING included with this
1066 + *  distribution); if not, write to the Free Software Foundation, Inc.,
1067 + *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1068 + */
1069 +
1070 +#include "syshead.h"
1071 +
1072 +#if P2MP_SERVER
1073 +
1074 +#include "mroute.h"
1075 +#include "proto.h"
1076 +#include "error.h"
1077 +#include "socket.h"
1078 +
1079 +#include "memdbg.h"
1080 +
1081 +void
1082 +mroute_addr_init (struct mroute_addr *addr)
1083 +{
1084 +  CLEAR (*addr);
1085 +}
1086 +
1087 +/*
1088 + * Ethernet multicast addresses.
1089 + */
1090 +
1091 +static inline bool
1092 +is_mac_mcast_addr (const uint8_t *mac)
1093 +{
1094 +  return (bool) mac[0] & 1;
1095 +}
1096 +
1097 +static inline bool
1098 +is_mac_mcast_maddr (const struct mroute_addr *addr)
1099 +{
1100 +  return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER && is_mac_mcast_addr (addr->addr); 
1101 +}
1102 +
1103 +/*
1104 + * Don't learn certain addresses.
1105 + */
1106 +bool
1107 +mroute_learnable_address (const struct mroute_addr *addr)
1108 +{
1109 +  int i;
1110 +  bool not_all_zeros = false;
1111 +  bool not_all_ones = false;
1112 +
1113 +  for (i = 0; i < addr->len; ++i)
1114 +    {
1115 +      int b = addr->addr[i];
1116 +      if (b != 0x00)
1117 +       not_all_zeros = true;
1118 +      if (b != 0xFF)
1119 +       not_all_ones = true;
1120 +    }
1121 +  return not_all_zeros && not_all_ones && !is_mac_mcast_maddr (addr);
1122 +}
1123 +
1124 +static inline void
1125 +mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
1126 +{
1127 +  if (ma)
1128 +    {
1129 +      ma->type = MR_ADDR_IPV4 | mask;
1130 +      ma->netbits = 0;
1131 +      ma->len = 4;
1132 +      *(in_addr_t*)ma->addr = src;
1133 +    }
1134 +}
1135 +
1136 +static inline void
1137 +mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
1138 +{
1139 +  if (ma)
1140 +    {
1141 +      ma->type = MR_ADDR_IPV6 | mask;
1142 +      ma->netbits = 0;
1143 +      ma->len = 16;
1144 +      *(struct in6_addr *)ma->addr = src;
1145 +    }
1146 +}
1147 +
1148 +static inline bool
1149 +mroute_is_mcast (const in_addr_t addr)
1150 +{
1151 +  return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
1152 +}
1153 +
1154 +/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies 
1155 + *                 the address as being a multicast address"
1156 + */
1157 +static inline bool
1158 +mroute_is_mcast_ipv6 (const struct in6_addr addr)
1159 +{
1160 +  return (addr.s6_addr[0] == 0xff);
1161 +}
1162 +
1163 +#ifdef ENABLE_PF
1164 +
1165 +static unsigned int
1166 +mroute_extract_addr_arp (struct mroute_addr *src,
1167 +                        struct mroute_addr *dest,
1168 +                        const struct buffer *buf)
1169 +{
1170 +  unsigned int ret = 0;
1171 +  if (BLEN (buf) >= (int) sizeof (struct openvpn_arp))
1172 +    {
1173 +      const struct openvpn_arp *arp = (const struct openvpn_arp *) BPTR (buf);
1174 +      if (arp->mac_addr_type == htons(0x0001)
1175 +         && arp->proto_addr_type == htons(0x0800)
1176 +         && arp->mac_addr_size == 0x06
1177 +         && arp->proto_addr_size == 0x04)
1178 +       {
1179 +         mroute_get_in_addr_t (src, arp->ip_src, MR_ARP);
1180 +         mroute_get_in_addr_t (dest, arp->ip_dest, MR_ARP);
1181 +
1182 +         /* multicast packet? */
1183 +         if (mroute_is_mcast (arp->ip_dest))
1184 +           ret |= MROUTE_EXTRACT_MCAST;
1185 +
1186 +         ret |= MROUTE_EXTRACT_SUCCEEDED;
1187 +       }
1188 +    }
1189 +  return ret;
1190 +}
1191 +
1192 +#endif
1193 +
1194 +unsigned int
1195 +mroute_extract_addr_ipv4 (struct mroute_addr *src,
1196 +                         struct mroute_addr *dest,
1197 +                         const struct buffer *buf)
1198 +{
1199 +  unsigned int ret = 0;
1200 +  static bool ipv6warned = false;
1201 +
1202 +  if (BLEN (buf) >= 1)
1203 +    {
1204 +      switch (OPENVPN_IPH_GET_VER (*BPTR(buf)))
1205 +       {
1206 +       case 4:
1207 +         if (BLEN (buf) >= (int) sizeof (struct openvpn_iphdr))
1208 +           {
1209 +             const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR (buf);
1210 +
1211 +             mroute_get_in_addr_t (src, ip->saddr, 0);
1212 +             mroute_get_in_addr_t (dest, ip->daddr, 0);
1213 +
1214 +             /* multicast packet? */
1215 +             if (mroute_is_mcast (ip->daddr))
1216 +               ret |= MROUTE_EXTRACT_MCAST;
1217 +
1218 +             /* IGMP message? */
1219 +             if (ip->protocol == OPENVPN_IPPROTO_IGMP)
1220 +               ret |= MROUTE_EXTRACT_IGMP;
1221 +
1222 +             ret |= MROUTE_EXTRACT_SUCCEEDED;
1223 +           }
1224 +         break;
1225 +       case 6:
1226 +         {
1227 +            if( !ipv6warned ) {
1228 +              msg (M_WARN, "IPv6 in tun mode is not supported in OpenVPN 2.2");
1229 +              ipv6warned = true;
1230 +            }
1231 +           break;
1232 +         }
1233 +       }
1234 +    }
1235 +  return ret;
1236 +}
1237 +
1238 +unsigned int
1239 +mroute_extract_addr_ether (struct mroute_addr *src,
1240 +                          struct mroute_addr *dest,
1241 +                          struct mroute_addr *esrc,
1242 +                          struct mroute_addr *edest,
1243 +                          const struct buffer *buf)
1244 +{
1245 +  unsigned int ret = 0;
1246 +  if (BLEN (buf) >= (int) sizeof (struct openvpn_ethhdr))
1247 +    {
1248 +      const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR (buf);
1249 +      if (src)
1250 +       {
1251 +         src->type = MR_ADDR_ETHER;
1252 +         src->netbits = 0;
1253 +         src->len = 6;
1254 +         memcpy (src->addr, eth->source, 6);
1255 +       }
1256 +      if (dest)
1257 +       {
1258 +         dest->type = MR_ADDR_ETHER;
1259 +         dest->netbits = 0;
1260 +         dest->len = 6;
1261 +         memcpy (dest->addr, eth->dest, 6);
1262 +
1263 +         /* ethernet broadcast/multicast packet? */
1264 +         if (is_mac_mcast_addr (eth->dest))
1265 +           ret |= MROUTE_EXTRACT_BCAST;
1266 +       }
1267 +         
1268 +      ret |= MROUTE_EXTRACT_SUCCEEDED;
1269 +
1270 +#ifdef ENABLE_PF
1271 +      if (esrc || edest)
1272 +       {
1273 +         struct buffer b = *buf;
1274 +         if (buf_advance (&b, sizeof (struct openvpn_ethhdr)))
1275 +           {
1276 +             switch (ntohs (eth->proto))
1277 +               {
1278 +               case OPENVPN_ETH_P_IPV4:
1279 +                 ret |= (mroute_extract_addr_ipv4 (esrc, edest, &b) << MROUTE_SEC_SHIFT);
1280 +                 break;
1281 +               case OPENVPN_ETH_P_ARP:
1282 +                 ret |= (mroute_extract_addr_arp (esrc, edest, &b) << MROUTE_SEC_SHIFT);
1283 +                 break;
1284 +               }
1285 +           }
1286 +       }
1287 +#endif
1288 +    }
1289 +  return ret;
1290 +}
1291 +
1292 +/*
1293 + * Translate a struct openvpn_sockaddr (osaddr)
1294 + * to a struct mroute_addr (addr).
1295 + */
1296 +bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
1297 +                                     const struct openvpn_sockaddr *osaddr,
1298 +                                     bool use_port)
1299 +{
1300 +  if (osaddr->sa.sin_family == AF_INET)
1301 +    {
1302 +      if (use_port)
1303 +       {
1304 +         addr->type = MR_ADDR_IPV4 | MR_WITH_PORT;
1305 +         addr->netbits = 0;
1306 +         addr->len = 6;
1307 +         memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
1308 +         memcpy (addr->addr + 4, &osaddr->sa.sin_port, 2);
1309 +       }
1310 +      else
1311 +       {
1312 +         addr->type = MR_ADDR_IPV4;
1313 +         addr->netbits = 0;
1314 +         addr->len = 4;
1315 +         memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
1316 +       }
1317 +      return true;
1318 +    }
1319 +  return false;
1320 +}
1321 +
1322 +/*
1323 + * Zero off the host bits in an address, leaving
1324 + * only the network bits, using the netbits member of
1325 + * struct mroute_addr as the controlling parameter.
1326 + *
1327 + * TODO: this is called for route-lookup for every yet-unhashed
1328 + * destination address, so for lots of active net-iroutes, this
1329 + * might benefit from some "zeroize 32 bit at a time" improvements
1330 + */
1331 +void
1332 +mroute_addr_mask_host_bits (struct mroute_addr *ma)
1333 +{
1334 +  in_addr_t addr = ntohl(*(in_addr_t*)ma->addr);
1335 +  if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
1336 +    {
1337 +      addr &= netbits_to_netmask (ma->netbits);
1338 +      *(in_addr_t*)ma->addr = htonl (addr);
1339 +    }
1340 +  else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
1341 +    {
1342 +      int byte = ma->len-1;            /* rightmost byte in address */
1343 +      int bits_to_clear = 128 - ma->netbits;
1344 +
1345 +      while( byte >= 0 && bits_to_clear > 0 )
1346 +        {
1347 +         if ( bits_to_clear >= 8 )
1348 +           { ma->addr[byte--] = 0; bits_to_clear -= 8; }
1349 +         else
1350 +           { ma->addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
1351 +        }
1352 +      ASSERT( bits_to_clear == 0 );
1353 +    }
1354 +  else
1355 +      ASSERT(0);
1356 +}
1357 +
1358 +/*
1359 + * The mroute_addr hash function takes into account the
1360 + * address type, number of bits in the network address,
1361 + * and the actual address.
1362 + */
1363 +uint32_t
1364 +mroute_addr_hash_function (const void *key, uint32_t iv)
1365 +{
1366 +  return hash_func (mroute_addr_hash_ptr ((const struct mroute_addr *) key),
1367 +                   mroute_addr_hash_len ((const struct mroute_addr *) key),
1368 +                   iv);
1369 +}
1370 +
1371 +bool
1372 +mroute_addr_compare_function (const void *key1, const void *key2)
1373 +{
1374 +  return mroute_addr_equal ((const struct mroute_addr *) key1,
1375 +                           (const struct mroute_addr *) key2);
1376 +}
1377 +
1378 +const char *
1379 +mroute_addr_print (const struct mroute_addr *ma,
1380 +                  struct gc_arena *gc)
1381 +{
1382 +  return mroute_addr_print_ex (ma, MAPF_IA_EMPTY_IF_UNDEF, gc);
1383 +}
1384 +
1385 +const char *
1386 +mroute_addr_print_ex (const struct mroute_addr *ma,
1387 +                     const unsigned int flags,
1388 +                     struct gc_arena *gc)
1389 +{
1390 +  struct buffer out = alloc_buf_gc (64, gc);
1391 +  if (ma)
1392 +    {
1393 +      struct mroute_addr maddr = *ma;
1394 +
1395 +      switch (maddr.type & MR_ADDR_MASK)
1396 +       {
1397 +       case MR_ADDR_ETHER:
1398 +         buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc)); 
1399 +         break;
1400 +       case MR_ADDR_IPV4:
1401 +         {
1402 +           struct buffer buf;
1403 +           in_addr_t addr;
1404 +           int port;
1405 +           bool status;
1406 +           buf_set_read (&buf, maddr.addr, maddr.len);
1407 +           addr = buf_read_u32 (&buf, &status);
1408 +           if (status)
1409 +             {
1410 +               if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
1411 +                 buf_printf (&out, "ARP/");
1412 +               buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc));
1413 +               if (maddr.type & MR_WITH_NETBITS)
1414 +                 {
1415 +                   if (flags & MAPF_SUBNET)
1416 +                     {
1417 +                       const in_addr_t netmask = netbits_to_netmask (maddr.netbits);
1418 +                       buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc));
1419 +                     }
1420 +                   else
1421 +                     buf_printf (&out, "/%d", maddr.netbits);
1422 +                 }
1423 +             }
1424 +           if (maddr.type & MR_WITH_PORT)
1425 +             {
1426 +               port = buf_read_u16 (&buf);
1427 +               if (port >= 0)
1428 +                 buf_printf (&out, ":%d", port);
1429 +             }
1430 +         }
1431 +         break;
1432 +       case MR_ADDR_IPV6:
1433 +         {
1434 +           buf_printf (&out, "%s",
1435 +                 print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc)); 
1436 +           if (maddr.type & MR_WITH_NETBITS)
1437 +             {
1438 +               buf_printf (&out, "/%d", maddr.netbits);
1439 +             }
1440 +           }
1441 +           break;
1442 +         default:
1443 +           buf_printf (&out, "UNKNOWN"); 
1444 +           break;
1445 +         }
1446 +       return BSTR (&out);
1447 +      }
1448 +    else
1449 +      return "[NULL]";
1450 +  }
1451 +
1452 +/*
1453 + * mroute_helper's main job is keeping track of
1454 + * currently used CIDR netlengths, so we don't
1455 + * have to cycle through all 33.
1456 + */
1457 +
1458 +struct mroute_helper *
1459 +mroute_helper_init (int ageable_ttl_secs)
1460 +{
1461 +  struct mroute_helper *mh;
1462 +  ALLOC_OBJ_CLEAR (mh, struct mroute_helper);
1463 +  mh->ageable_ttl_secs = ageable_ttl_secs;
1464 +  return mh;
1465 +}
1466 +
1467 +static void
1468 +mroute_helper_regenerate (struct mroute_helper *mh)
1469 +{
1470 +  int i, j = 0;
1471 +  for (i = MR_HELPER_NET_LEN - 1; i >= 0; --i)
1472 +    {
1473 +      if (mh->net_len_refcount[i] > 0)
1474 +       mh->net_len[j++] = (uint8_t) i;
1475 +    }
1476 +  mh->n_net_len = j;
1477 +
1478 +#ifdef ENABLE_DEBUG
1479 +  if (check_debug_level (D_MULTI_DEBUG))
1480 +    {
1481 +      struct gc_arena gc = gc_new ();
1482 +      struct buffer out = alloc_buf_gc (256, &gc);
1483 +      buf_printf (&out, "MROUTE CIDR netlen:");
1484 +      for (i = 0; i < mh->n_net_len; ++i)
1485 +       {
1486 +         buf_printf (&out, " /%d", mh->net_len[i]);
1487 +       }
1488 +      dmsg (D_MULTI_DEBUG, "%s", BSTR (&out));
1489 +      gc_free (&gc);
1490 +    }
1491 +#endif
1492 +}
1493 +
1494 +void
1495 +mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir)
1496 +{
1497 +  if (ir->netbits >= 0)
1498 +    {
1499 +      ASSERT (ir->netbits < MR_HELPER_NET_LEN);
1500 +      ++mh->cache_generation;
1501 +      ++mh->net_len_refcount[ir->netbits];
1502 +      if (mh->net_len_refcount[ir->netbits] == 1)
1503 +       mroute_helper_regenerate (mh);
1504 +    }
1505 +}
1506 +
1507 +void
1508 +mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir)
1509 +{
1510 +  if (ir->netbits >= 0)
1511 +    {
1512 +      ASSERT (ir->netbits < MR_HELPER_NET_LEN);
1513 +      ++mh->cache_generation;
1514 +      --mh->net_len_refcount[ir->netbits];
1515 +      ASSERT (mh->net_len_refcount[ir->netbits] >= 0);
1516 +      if (!mh->net_len_refcount[ir->netbits])
1517 +       mroute_helper_regenerate (mh);
1518 +    }
1519 +}
1520 +
1521 +/* this is a bit inelegant, we really should have a helper to that 
1522 + * is only passed the netbits value, and not the whole struct iroute *
1523 + * - thus one helper could do IPv4 and IPv6.  For the sake of "not change
1524 + * code unrelated to IPv4" this is left for later cleanup, for now.
1525 + */
1526 +void
1527 +mroute_helper_add_iroute6 (struct mroute_helper *mh, 
1528 +                           const struct iroute_ipv6 *ir6)
1529 +{
1530 +  if (ir6->netbits >= 0)
1531 +    {
1532 +      ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
1533 +      ++mh->cache_generation;
1534 +      ++mh->net_len_refcount[ir6->netbits];
1535 +      if (mh->net_len_refcount[ir6->netbits] == 1)
1536 +       mroute_helper_regenerate (mh);
1537 +    }
1538 +}
1539 +
1540 +void
1541 +mroute_helper_del_iroute6 (struct mroute_helper *mh, 
1542 +                          const struct iroute_ipv6 *ir6)
1543 +{
1544 +  if (ir6->netbits >= 0)
1545 +    {
1546 +      ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
1547 +      ++mh->cache_generation;
1548 +      --mh->net_len_refcount[ir6->netbits];
1549 +      ASSERT (mh->net_len_refcount[ir6->netbits] >= 0);
1550 +      if (!mh->net_len_refcount[ir6->netbits])
1551 +       mroute_helper_regenerate (mh);
1552 +    }
1553 +}
1554 +
1555 +void
1556 +mroute_helper_free (struct mroute_helper *mh)
1557 +{
1558 +  free (mh);
1559 +}
1560 +
1561 +#else
1562 +static void dummy(void) {}
1563 +#endif /* P2MP_SERVER */
1564 diff -durN openvpn-2.2.2.orig/mroute.h openvpn-2.2.2/mroute.h
1565 --- openvpn-2.2.2.orig/mroute.h 2011-12-13 17:58:56.000000000 +0100
1566 +++ openvpn-2.2.2/mroute.h      2012-06-01 10:40:28.000000000 +0200
1567 @@ -85,7 +85,7 @@
1568  /*
1569   * Number of bits in an address.  Should be raised for IPv6.
1570   */
1571 -#define MR_HELPER_NET_LEN 32
1572 +#define MR_HELPER_NET_LEN 129
1573  
1574  /*
1575   * Used to help maintain CIDR routing table.
1576 @@ -127,6 +127,8 @@
1577  void mroute_helper_free (struct mroute_helper *mh);
1578  void mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir);
1579  void mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir);
1580 +void mroute_helper_add_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
1581 +void mroute_helper_del_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
1582  
1583  /*
1584   * Given a raw packet in buf, return the src and dest
1585 diff -durN openvpn-2.2.2.orig/multi.c openvpn-2.2.2/multi.c
1586 --- openvpn-2.2.2.orig/multi.c  2011-12-13 17:58:56.000000000 +0100
1587 +++ openvpn-2.2.2/multi.c       2012-06-01 10:40:28.000000000 +0200
1588 @@ -316,25 +316,18 @@
1589     */
1590    if (t->options.ifconfig_pool_defined)
1591      {
1592 -      if (dev == DEV_TYPE_TAP)
1593 -       {
1594 -         m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_INDIV,
1595 -                                                t->options.ifconfig_pool_start,
1596 -                                                t->options.ifconfig_pool_end,
1597 -                                                t->options.duplicate_cn);
1598 -       }
1599 -      else if (dev == DEV_TYPE_TUN)
1600 -       {
1601 -         m->ifconfig_pool = ifconfig_pool_init (
1602 -           (t->options.topology == TOP_NET30) ? IFCONFIG_POOL_30NET : IFCONFIG_POOL_INDIV,
1603 -           t->options.ifconfig_pool_start,
1604 -           t->options.ifconfig_pool_end,
1605 -           t->options.duplicate_cn);
1606 -       }
1607 -      else
1608 -       {
1609 -         ASSERT (0);
1610 -       }
1611 +      int pool_type = IFCONFIG_POOL_INDIV;
1612 +
1613 +      if ( dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30 )
1614 +       pool_type = IFCONFIG_POOL_30NET;
1615 +
1616 +      m->ifconfig_pool = ifconfig_pool_init (pool_type,
1617 +                                t->options.ifconfig_pool_start,
1618 +                                t->options.ifconfig_pool_end,
1619 +                                t->options.duplicate_cn,
1620 +                                t->options.ifconfig_ipv6_pool_defined,
1621 +                                t->options.ifconfig_ipv6_pool_base,
1622 +                                t->options.ifconfig_ipv6_pool_netbits );
1623  
1624        /* reload pool data from file */
1625        if (t->c1.ifconfig_pool_persist)
1626 @@ -429,10 +422,14 @@
1627                    struct multi_instance *mi)
1628  {
1629    const struct iroute *ir;
1630 +  const struct iroute_ipv6 *ir6;
1631    if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
1632      {
1633        for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next)
1634         mroute_helper_del_iroute (m->route_helper, ir);
1635 +
1636 +      for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
1637 +       mroute_helper_del_iroute6 (m->route_helper, ir6);
1638      }
1639  }
1640  
1641 @@ -1078,6 +1075,37 @@
1642    }
1643  }
1644  
1645 +static struct multi_instance *
1646 +multi_learn_in6_addr  (struct multi_context *m,
1647 +                      struct multi_instance *mi,
1648 +                      struct in6_addr a6,
1649 +                      int netbits, /* -1 if host route, otherwise # of network bits in address */
1650 +                      bool primary)
1651 +{
1652 +  struct mroute_addr addr;
1653 +
1654 +  addr.len = 16;
1655 +  addr.type = MR_ADDR_IPV6;
1656 +  addr.netbits = 0;
1657 +  memcpy( &addr.addr, &a6, sizeof(a6) );
1658 +
1659 +  if (netbits >= 0)
1660 +    {
1661 +      addr.type |= MR_WITH_NETBITS;
1662 +      addr.netbits = (uint8_t) netbits;
1663 +      mroute_addr_mask_host_bits( &addr );
1664 +    }
1665 +
1666 +  {
1667 +    struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0);
1668 +#ifdef MANAGEMENT_DEF_AUTH
1669 +    if (management && owner)
1670 +      management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary);
1671 +#endif
1672 +    return owner;
1673 +  }
1674 +}
1675 +
1676  /*
1677   * A new client has connected, add routes (server -> client)
1678   * to internal routing table.
1679 @@ -1088,6 +1116,7 @@
1680  {
1681    struct gc_arena gc = gc_new ();
1682    const struct iroute *ir;
1683 +  const struct iroute_ipv6 *ir6;
1684    if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
1685      {
1686        mi->did_iroutes = true;
1687 @@ -1107,6 +1136,22 @@
1688        
1689           multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false);
1690         }
1691 +      for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
1692 +       {
1693 +         if (ir6->netbits >= 0)
1694 +           msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s",
1695 +                print_in6_addr (ir6->network, 0, &gc),
1696 +                ir6->netbits,
1697 +                multi_instance_string (mi, false, &gc));
1698 +         else
1699 +           msg (D_MULTI_LOW, "MULTI: internal route %s -> %s",
1700 +                print_in6_addr (ir6->network, 0, &gc),
1701 +                multi_instance_string (mi, false, &gc));
1702 +
1703 +         mroute_helper_add_iroute6 (m->route_helper, ir6);
1704 +      
1705 +         multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false);
1706 +       }
1707      }
1708    gc_free (&gc);
1709  }
1710 @@ -1192,21 +1237,37 @@
1711        mi->context.c2.push_ifconfig_defined = true;
1712        mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
1713        mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
1714 +
1715 +      /* the current implementation does not allow "static IPv4, pool IPv6",
1716 +       * (see below) so issue a warning if that happens - don't break the
1717 +       * session, though, as we don't even know if this client WANTS IPv6
1718 +       */
1719 +      if ( mi->context.c1.tuntap->ipv6 &&
1720 +          mi->context.options.ifconfig_ipv6_pool_defined &&
1721 +          ! mi->context.options.push_ifconfig_ipv6_defined )
1722 +       {
1723 +         msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work.  Use --ifconfig-ipv6-push for IPv6 then." );
1724 +       }
1725      }
1726    else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */
1727      {
1728        in_addr_t local=0, remote=0;
1729 +      struct in6_addr remote_ipv6;
1730        const char *cn = NULL;
1731  
1732        if (!mi->context.options.duplicate_cn)
1733         cn = tls_common_name (mi->context.c2.tls_multi, true);
1734  
1735 -      mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, cn);
1736 +      mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, &remote_ipv6, cn);
1737        if (mi->vaddr_handle >= 0)
1738         {
1739           const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap);
1740           const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap);
1741  
1742 +         msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", 
1743 +                   print_in_addr_t( remote, 0, &gc ),
1744 +                   print_in6_addr( remote_ipv6, 0, &gc ) );
1745 +
1746           /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */
1747           mi->context.c2.push_ifconfig_local = remote;
1748           if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET))
1749 @@ -1228,12 +1289,46 @@
1750           else
1751             msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s",
1752                  multi_instance_string (mi, false, &gc));
1753 +
1754 +         if ( mi->context.options.ifconfig_ipv6_pool_defined )
1755 +           {
1756 +             mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6;
1757 +             mi->context.c2.push_ifconfig_ipv6_remote = 
1758 +                   mi->context.c1.tuntap->local_ipv6;
1759 +             mi->context.c2.push_ifconfig_ipv6_netbits = 
1760 +                   mi->context.options.ifconfig_ipv6_pool_netbits;
1761 +             mi->context.c2.push_ifconfig_ipv6_defined = true;
1762 +           }
1763         }
1764        else
1765         {
1766           msg (D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available");
1767         }
1768      }
1769 +
1770 +  /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the 
1771 +   * pool handling with IPv4, the combination "static IPv4, dynamic IPv6"
1772 +   * will fail (because no pool will be allocated in this case).
1773 +   * OTOH, this doesn't make too much sense in reality - and the other
1774 +   * way round ("dynamic IPv4, static IPv6") or "both static" makes sense
1775 +   * -> and so it's implemented right now
1776 +   */
1777 +  if ( mi->context.c1.tuntap->ipv6 &&
1778 +       mi->context.options.push_ifconfig_ipv6_defined )
1779 +    {
1780 +      mi->context.c2.push_ifconfig_ipv6_local = 
1781 +           mi->context.options.push_ifconfig_ipv6_local;
1782 +      mi->context.c2.push_ifconfig_ipv6_remote = 
1783 +           mi->context.options.push_ifconfig_ipv6_remote;
1784 +      mi->context.c2.push_ifconfig_ipv6_netbits = 
1785 +           mi->context.options.push_ifconfig_ipv6_netbits;
1786 +      mi->context.c2.push_ifconfig_ipv6_defined = true;
1787 +
1788 +      msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d", 
1789 +           print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ),
1790 +           mi->context.c2.push_ifconfig_ipv6_netbits );
1791 +    }
1792 +
1793    gc_free (&gc);
1794  }
1795  
1796 @@ -1272,6 +1367,11 @@
1797                             SA_SET_IF_NONZERO);
1798         }
1799      }
1800 +
1801 +    /* TODO: I'm not exactly sure what these environment variables are
1802 +     *       used for, but if we have them for IPv4, we should also have
1803 +     *       them for IPv6, no?
1804 +     */
1805  }
1806  
1807  /*
1808 @@ -1661,6 +1761,15 @@
1809                        print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc));
1810                 }
1811  
1812 +             if (mi->context.c2.push_ifconfig_ipv6_defined)
1813 +               {
1814 +                 multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true);
1815 +                 /* TODO: find out where addresses are "unlearned"!! */
1816 +                 msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s",
1817 +                      multi_instance_string (mi, false, &gc),
1818 +                      print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc));
1819 +               }
1820 +
1821               /* add routes locally, pointing to new client, if
1822                  --iroute options have been specified */
1823               multi_add_iroutes (m, mi);
1824 diff -durN openvpn-2.2.2.orig/openvpn.8 openvpn-2.2.2/openvpn.8
1825 --- openvpn-2.2.2.orig/openvpn.8        2011-12-13 17:58:56.000000000 +0100
1826 +++ openvpn-2.2.2/openvpn.8     2012-06-01 10:40:28.000000000 +0200
1827 @@ -794,6 +794,8 @@
1828  .B \-\-dev tunX.
1829  A warning will be displayed
1830  if no specific IPv6 TUN support for your OS has been compiled into OpenVPN.
1831 +
1832 +See below for further IPv6-related configuration options.
1833  .\"*********************************************************
1834  .TP
1835  .B \-\-dev-node node
1836 @@ -4949,6 +4951,57 @@
1837  .B \-\-verb
1838  option can be used BEFORE this option to produce debugging information.
1839  .\"*********************************************************
1840 +.SS IPv6 Related Options
1841 +.\"*********************************************************
1842 +The following options exist to support IPv6 tunneling in peer-to-peer
1843 +and client-server mode.  As of now, this is just very basic
1844 +documentation of the IPv6-related options. More documentation can be
1845 +found on http://www.greenie.net/ipv6/openvpn.html.
1846 +.TP
1847 +.B --ifconfig-ipv6 ipv6addr/bits ipv6remote
1848 +configure IPv6 address
1849 +.B ipv6addr/bits
1850 +on the ``tun'' device.  The second parameter is used as route target for
1851 +.B --route-ipv6
1852 +if no gateway is specified.
1853 +.TP
1854 +.B --route-ipv6 ipv6addr/bits [gateway] [metric]
1855 +setup IPv6 routing in the system to send the specified IPv6 network
1856 +into OpenVPN's ``tun'' device
1857 +.TP
1858 +.B --server-ipv6 ipv6addr/bits
1859 +convenience-function to enable a number of IPv6 related options at
1860 +once, namely
1861 +.B --ifconfig-ipv6, --ifconfig-ipv6-pool, --tun-ipv6
1862 +and
1863 +.B --push tun-ipv6
1864 +Is only accepted if ``--mode server'' or ``--server'' is set.
1865 +.TP
1866 +.B --ifconfig-ipv6-pool ipv6addr/bits
1867 +Specify an IPv6 address pool for dynamic assignment to clients.  The
1868 +pool starts at
1869 +.B ipv6addr
1870 +and increments by +1 for every new client (linear mode).  The
1871 +.B /bits
1872 +setting controls the size of the pool.
1873 +.TP
1874 +.B --ifconfig-ipv6-push ipv6addr/bits ipv6remote
1875 +for ccd/ per-client static IPv6 interface configuration, see
1876 +.B --client-config-dir
1877 +and
1878 +.B --ifconfig-push
1879 +for more details.
1880 +.TP
1881 +.B --iroute-ipv6 ipv6addr/bits
1882 +for ccd/ per-client static IPv6 route configuration, see
1883 +.B --iroute
1884 +for more details how to setup and use this, and how
1885 +.B --iroute
1886 +and
1887 +.B --route
1888 +interact.
1889 +
1890 +.\"*********************************************************
1891  .SH SCRIPTING AND ENVIRONMENTAL VARIABLES
1892  OpenVPN exports a series
1893  of environmental variables for use by user-defined scripts.
1894 diff -durN openvpn-2.2.2.orig/openvpn.h openvpn-2.2.2/openvpn.h
1895 --- openvpn-2.2.2.orig/openvpn.h        2011-12-13 17:58:56.000000000 +0100
1896 +++ openvpn-2.2.2/openvpn.h     2012-06-01 10:40:28.000000000 +0200
1897 @@ -165,6 +165,9 @@
1898    /* list of --route directives */
1899    struct route_list *route_list;
1900  
1901 +  /* list of --route-ipv6 directives */
1902 +  struct route_ipv6_list *route_ipv6_list;
1903 +
1904    /* --status file */
1905    struct status_output *status_output;
1906    bool status_output_owned;
1907 @@ -417,6 +420,11 @@
1908    in_addr_t push_ifconfig_local;
1909    in_addr_t push_ifconfig_remote_netmask;
1910  
1911 +  bool            push_ifconfig_ipv6_defined;
1912 +  struct in6_addr push_ifconfig_ipv6_local;
1913 +  int             push_ifconfig_ipv6_netbits;
1914 +  struct in6_addr push_ifconfig_ipv6_remote;
1915 +
1916    /* client authentication state, CAS_SUCCEEDED must be 0 */
1917  # define CAS_SUCCEEDED 0
1918  # define CAS_PENDING   1
1919 diff -durN openvpn-2.2.2.orig/options.c openvpn-2.2.2/options.c
1920 --- openvpn-2.2.2.orig/options.c        2011-12-13 17:58:56.000000000 +0100
1921 +++ openvpn-2.2.2/options.c     2012-06-01 10:40:28.000000000 +0200
1922 @@ -79,6 +79,7 @@
1923  #ifdef ENABLE_EUREPHIA
1924    " [eurephia]"
1925  #endif
1926 +  " [IPv6 payload 20110522-1 (2.2.0)]"
1927    " built on " __DATE__
1928  ;
1929  
1930 @@ -172,6 +173,8 @@
1931    "                  addresses outside of the subnets used by either peer.\n"
1932    "                  TAP: configure device to use IP address l as a local\n"
1933    "                  endpoint and rn as a subnet mask.\n"
1934 +  "--ifconfig-ipv6 l r : configure device to use IPv6 address l as local\n"
1935 +  "                      endpoint (as a /64) and r as remote endpoint\n"
1936    "--ifconfig-noexec : Don't actually execute ifconfig/netsh command, instead\n"
1937    "                    pass --ifconfig parms by environment to scripts.\n"
1938    "--ifconfig-nowarn : Don't warn if the --ifconfig option on this side of the\n"
1939 @@ -182,6 +185,10 @@
1940    "                  netmask default: 255.255.255.255\n"
1941    "                  gateway default: taken from --route-gateway or --ifconfig\n"
1942    "                  Specify default by leaving blank or setting to \"nil\".\n"
1943 +  "--route-ipv6 network/bits [gateway] [metric] :\n"
1944 +  "                  Add IPv6 route to routing table after connection\n"
1945 +  "                  is established.  Multiple routes can be specified.\n"
1946 +  "                  gateway default: taken from --route-ipv6-gateway or --ifconfig\n"
1947    "--max-routes n :  Specify the maximum number of routes that may be defined\n"
1948    "                  or pulled from a server.\n"
1949    "--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n"
1950 @@ -370,6 +377,7 @@
1951    "\n"
1952    "Multi-Client Server options (when --mode server is used):\n"
1953    "--server network netmask : Helper option to easily configure server mode.\n"
1954 +  "--server-ipv6 network/bits : Configure IPv6 server mode.\n"
1955    "--server-bridge [IP netmask pool-start-IP pool-end-IP] : Helper option to\n"
1956    "                    easily configure ethernet bridging server mode.\n"
1957    "--push \"option\" : Push a config file option back to the peer for remote\n"
1958 @@ -383,10 +391,16 @@
1959    "--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n"
1960    "                  data to file, at seconds intervals (default=600).\n"
1961    "                  If seconds=0, file will be treated as read-only.\n"
1962 +  "--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n"
1963 +  "                  to be dynamically allocated to connecting clients.\n"
1964    "--ifconfig-push local remote-netmask : Push an ifconfig option to remote,\n"
1965    "                  overrides --ifconfig-pool dynamic allocation.\n"
1966    "                  Only valid in a client-specific config file.\n"
1967 +  "--ifconfig-ipv6-push local/bits remote : Push an ifconfig-ipv6 option to\n"
1968 +  "                  remote, overrides --ifconfig-ipv6-pool allocation.\n"
1969 +  "                  Only valid in a client-specific config file.\n"
1970    "--iroute network [netmask] : Route subnet to client.\n"
1971 +  "--iroute-ipv6 network/bits : Route IPv6 subnet to client.\n"
1972    "                  Sets up internal routes only.\n"
1973    "                  Only valid in a client-specific config file.\n"
1974    "--disable       : Client is disabled.\n"
1975 @@ -871,6 +885,78 @@
1976    return ret;
1977  }
1978  
1979 +/* helper: parse a text string containing an IPv6 address + netbits
1980 + * in "standard format" (2001:dba::/32)
1981 + * "/nn" is optional, default to /64 if missing
1982 + *
1983 + * return true if parsing succeeded, modify *network and *netbits
1984 + * return address part without "/nn" in *printable_ipv6 (if != NULL)
1985 + */
1986 +bool
1987 +get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
1988 +              unsigned int * netbits, char ** printable_ipv6, int msglevel )
1989 +{
1990 +    int rc;
1991 +    char * sep, * endp;
1992 +    int bits;
1993 +    struct in6_addr t_network;
1994 +
1995 +    sep = strchr( prefix_str, '/' );
1996 +    if ( sep == NULL )
1997 +      {
1998 +       bits = 64;
1999 +      }
2000 +    else
2001 +      {
2002 +       bits = strtol( sep+1, &endp, 10 );
2003 +       if ( *endp != '\0' || bits < 0 || bits > 128 )
2004 +         {
2005 +           msg (msglevel, "IPv6 prefix '%s': invalid '/bits' spec", prefix_str);
2006 +           return false;
2007 +         }
2008 +      }
2009 +
2010 +    /* temporary replace '/' in caller-provided string with '\0', otherwise
2011 +     * inet_pton() will refuse prefix string
2012 +     * (alternative would be to strncpy() the prefix to temporary buffer)
2013 +     */
2014 +
2015 +    if ( sep != NULL ) *sep = '\0';
2016 +
2017 +    rc = inet_pton( AF_INET6, prefix_str, &t_network );
2018 +
2019 +    if ( rc == 1 && printable_ipv6 != NULL )
2020 +      {
2021 +       *printable_ipv6 = string_alloc( prefix_str, NULL );
2022 +      }
2023 +
2024 +    if ( sep != NULL ) *sep = '/';
2025 +
2026 +    if ( rc != 1 )
2027 +      {
2028 +       msg (msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str);
2029 +       return false;
2030 +      }
2031 +
2032 +    if ( netbits != NULL )
2033 +      {
2034 +       *netbits = bits;
2035 +      }
2036 +    if ( network != NULL )
2037 +      {
2038 +       *network = t_network;
2039 +      }
2040 +    return true;               /* parsing OK, values set */
2041 +}
2042 +
2043 +static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec )
2044 +{
2045 +    struct in6_addr t_addr;
2046 +    unsigned int t_bits;
2047 +
2048 +    return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, NULL, M_WARN );
2049 +}
2050 +
2051  static char *
2052  string_substitute (const char *src, int from, int to, struct gc_arena *gc)
2053  {
2054 @@ -989,6 +1075,8 @@
2055  #if P2MP_SERVER
2056    msg (D_SHOW_PARMS, "  server_network = %s", print_in_addr_t (o->server_network, 0, &gc));
2057    msg (D_SHOW_PARMS, "  server_netmask = %s", print_in_addr_t (o->server_netmask, 0, &gc));
2058 +  msg (D_SHOW_PARMS, "  server_network_ipv6 = %s", print_in6_addr (o->server_network_ipv6, 0, &gc) );
2059 +  SHOW_INT (server_netbits_ipv6);
2060    msg (D_SHOW_PARMS, "  server_bridge_ip = %s", print_in_addr_t (o->server_bridge_ip, 0, &gc));
2061    msg (D_SHOW_PARMS, "  server_bridge_netmask = %s", print_in_addr_t (o->server_bridge_netmask, 0, &gc));
2062    msg (D_SHOW_PARMS, "  server_bridge_pool_start = %s", print_in_addr_t (o->server_bridge_pool_start, 0, &gc));
2063 @@ -1009,6 +1097,9 @@
2064    msg (D_SHOW_PARMS, "  ifconfig_pool_netmask = %s", print_in_addr_t (o->ifconfig_pool_netmask, 0, &gc));
2065    SHOW_STR (ifconfig_pool_persist_filename);
2066    SHOW_INT (ifconfig_pool_persist_refresh_freq);
2067 +  SHOW_BOOL (ifconfig_ipv6_pool_defined);
2068 +  msg (D_SHOW_PARMS, "  ifconfig_ipv6_pool_base = %s", print_in6_addr (o->ifconfig_ipv6_pool_base, 0, &gc));
2069 +  SHOW_INT (ifconfig_ipv6_pool_netbits);
2070    SHOW_INT (n_bcast_buf);
2071    SHOW_INT (tcp_queue_limit);
2072    SHOW_INT (real_hash_size);
2073 @@ -1022,6 +1113,9 @@
2074    SHOW_BOOL (push_ifconfig_defined);
2075    msg (D_SHOW_PARMS, "  push_ifconfig_local = %s", print_in_addr_t (o->push_ifconfig_local, 0, &gc));
2076    msg (D_SHOW_PARMS, "  push_ifconfig_remote_netmask = %s", print_in_addr_t (o->push_ifconfig_remote_netmask, 0, &gc));
2077 +  SHOW_BOOL (push_ifconfig_ipv6_defined);
2078 +  msg (D_SHOW_PARMS, "  push_ifconfig_ipv6_local = %s/%d", print_in6_addr (o->push_ifconfig_ipv6_local, 0, &gc), o->push_ifconfig_ipv6_netbits );
2079 +  msg (D_SHOW_PARMS, "  push_ifconfig_ipv6_remote = %s", print_in6_addr (o->push_ifconfig_ipv6_remote, 0, &gc));
2080    SHOW_BOOL (enable_c2c);
2081    SHOW_BOOL (duplicate_cn);
2082    SHOW_INT (cf_max);
2083 @@ -1076,6 +1170,25 @@
2084    o->iroutes = ir;
2085  }
2086  
2087 +static void
2088 +option_iroute_ipv6 (struct options *o,
2089 +              const char *prefix_str,
2090 +              int msglevel)
2091 +{
2092 +  struct iroute_ipv6 *ir;
2093 +
2094 +  ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc);
2095 +
2096 +  if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, NULL, msglevel ) < 0 )
2097 +    {
2098 +      msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification",
2099 +          prefix_str);
2100 +      return;
2101 +    }
2102 +
2103 +  ir->next = o->iroutes_ipv6;
2104 +  o->iroutes_ipv6 = ir;
2105 +}
2106  #endif /* P2MP_SERVER */
2107  #endif /* P2MP */
2108  
2109 @@ -1113,6 +1226,13 @@
2110      options->routes = new_route_option_list (options->max_routes, &options->gc);
2111  }
2112  
2113 +void
2114 +rol6_check_alloc (struct options *options)
2115 +{
2116 +  if (!options->routes_ipv6)
2117 +    options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc);
2118 +}
2119 +
2120  #ifdef ENABLE_DEBUG
2121  static void
2122  show_connection_entry (const struct connection_entry *o)
2123 @@ -1203,6 +1323,9 @@
2124    SHOW_STR (ifconfig_remote_netmask);
2125    SHOW_BOOL (ifconfig_noexec);
2126    SHOW_BOOL (ifconfig_nowarn);
2127 +  SHOW_STR (ifconfig_ipv6_local);
2128 +  SHOW_INT (ifconfig_ipv6_netbits);
2129 +  SHOW_STR (ifconfig_ipv6_remote);
2130  
2131  #ifdef HAVE_GETTIMEOFDAY
2132    SHOW_INT (shaper);
2133 @@ -1863,8 +1986,10 @@
2134        if (options->connection_list)
2135         msg (M_USAGE, "<connection> cannot be used with --mode server");
2136  #endif
2137 +#if 0
2138        if (options->tun_ipv6)
2139         msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
2140 +#endif
2141        if (options->shaper)
2142         msg (M_USAGE, "--shaper cannot be used with --mode server");
2143        if (options->inetd)
2144 @@ -1889,6 +2014,11 @@
2145         msg (M_USAGE, "--up-delay cannot be used with --mode server");
2146        if (!options->ifconfig_pool_defined && options->ifconfig_pool_persist_filename)
2147         msg (M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool");
2148 +      if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local )
2149 +       msg (M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6");
2150 +      if (options->ifconfig_ipv6_local && !options->tun_ipv6 )
2151 +       msg (M_INFO, "Warning: --ifconfig-ipv6 without --tun-ipv6 will not do IPv6");
2152 +
2153        if (options->auth_user_pass_file)
2154         msg (M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)");
2155        if (options->ccd_exclusive && !options->client_config_dir)
2156 @@ -1920,6 +2050,8 @@
2157         */
2158        if (options->ifconfig_pool_defined || options->ifconfig_pool_persist_filename)
2159         msg (M_USAGE, "--ifconfig-pool/--ifconfig-pool-persist requires --mode server");
2160 +      if (options->ifconfig_ipv6_pool_defined)
2161 +       msg (M_USAGE, "--ifconfig-ipv6-pool requires --mode server");
2162        if (options->real_hash_size != defaults.real_hash_size
2163           || options->virtual_hash_size != defaults.virtual_hash_size)
2164         msg (M_USAGE, "--hash-size requires --mode server");
2165 @@ -2461,6 +2593,8 @@
2166                      o->topology,
2167                      o->ifconfig_local,
2168                      o->ifconfig_remote_netmask,
2169 +                    o->ifconfig_ipv6_local,
2170 +                    o->ifconfig_ipv6_remote,
2171                      (in_addr_t)0,
2172                      (in_addr_t)0,
2173                      false,
2174 @@ -3786,6 +3920,30 @@
2175           goto err;
2176         }
2177      }
2178 +  else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] )
2179 +    {
2180 +      unsigned int netbits;
2181 +      char * ipv6_local;
2182 +       
2183 +      VERIFY_PERMISSION (OPT_P_UP);
2184 +      if ( get_ipv6_addr( p[1], NULL, &netbits, &ipv6_local, msglevel ) &&
2185 +           ipv6_addr_safe( p[2] ) )
2186 +        {
2187 +         if ( netbits < 64 || netbits > 124 )
2188 +           {
2189 +             msg( msglevel, "ifconfig-ipv6: /netbits must be between 64 and 124, not '/%d'", netbits );
2190 +             goto err;
2191 +           }
2192 +         options->ifconfig_ipv6_local = ipv6_local;
2193 +         options->ifconfig_ipv6_netbits = netbits;
2194 +         options->ifconfig_ipv6_remote = p[2];
2195 +        }
2196 +      else
2197 +       {
2198 +         msg (msglevel, "ifconfig-ipv6 parms '%s' and '%s' must be valid addresses", p[1], p[2]);
2199 +         goto err;
2200 +       }
2201 +    }
2202    else if (streq (p[0], "ifconfig-noexec"))
2203      {
2204        VERIFY_PERMISSION (OPT_P_UP);
2205 @@ -4586,6 +4744,26 @@
2206         }
2207        add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]);
2208      }
2209 +  else if (streq (p[0], "route-ipv6") && p[1])
2210 +    {
2211 +      VERIFY_PERMISSION (OPT_P_ROUTE);
2212 +      rol6_check_alloc (options);
2213 +      if (pull_mode)
2214 +       {
2215 +         if (!ipv6_addr_safe_hexplusbits (p[1]))
2216 +           {
2217 +             msg (msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]);
2218 +             goto err;
2219 +           }
2220 +         if (p[2] && !ipv6_addr_safe (p[2]))
2221 +           {
2222 +             msg (msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]);
2223 +             goto err;
2224 +           }
2225 +         /* p[3] is metric, if present */
2226 +       }
2227 +      add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]);
2228 +    }
2229    else if (streq (p[0], "max-routes") && p[1])
2230      {
2231        int max_routes;
2232 @@ -4797,6 +4975,33 @@
2233             }
2234         }
2235      }
2236 +  else if (streq (p[0], "server-ipv6") && p[1] )
2237 +    {
2238 +      const int lev = M_WARN;
2239 +      struct in6_addr network;
2240 +      unsigned int netbits = 0;
2241 +
2242 +      VERIFY_PERMISSION (OPT_P_GENERAL);
2243 +      if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev) )
2244 +       {
2245 +         msg (msglevel, "error parsing --server-ipv6 parameter");
2246 +         goto err;
2247 +       }
2248 +      if ( netbits != 64 )
2249 +       {
2250 +         msg( msglevel, "--server-ipv6 settings: only /64 supported right now (not /%d)", netbits );
2251 +         goto err;
2252 +       }
2253 +      options->server_ipv6_defined = true;
2254 +      options->server_network_ipv6 = network;
2255 +      options->server_netbits_ipv6 = netbits;
2256 +
2257 +      if (p[2])                /* no "nopool" options or similar for IPv6 */
2258 +       {
2259 +         msg (msglevel, "error parsing --server-ipv6: %s is not a recognized flag", p[3]);
2260 +         goto err;
2261 +       }
2262 +    }
2263    else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4])
2264      {
2265        const int lev = M_WARN;
2266 @@ -4881,6 +5086,28 @@
2267        VERIFY_PERMISSION (OPT_P_GENERAL);
2268        options->topology = TOP_P2P;
2269      }
2270 +  else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] )
2271 +    {
2272 +      const int lev = M_WARN;
2273 +      struct in6_addr network;
2274 +      unsigned int netbits = 0;
2275 +
2276 +      VERIFY_PERMISSION (OPT_P_GENERAL);
2277 +      if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev ) )
2278 +       {
2279 +         msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters");
2280 +         goto err;
2281 +       }
2282 +      if ( netbits != 64 )
2283 +       {
2284 +         msg( msglevel, "--ifconfig-ipv6-pool settings: only /64 supported right now (not /%d)", netbits );
2285 +         goto err;
2286 +       }
2287 +
2288 +      options->ifconfig_ipv6_pool_defined = true;
2289 +      options->ifconfig_ipv6_pool_base = network;
2290 +      options->ifconfig_ipv6_pool_netbits = netbits;
2291 +    }
2292    else if (streq (p[0], "hash-size") && p[1] && p[2])
2293      {
2294        int real, virtual;
2295 @@ -5076,6 +5303,11 @@
2296         }
2297        option_iroute (options, p[1], netmask, msglevel);
2298      }
2299 +  else if (streq (p[0], "iroute-ipv6") && p[1])
2300 +    {
2301 +      VERIFY_PERMISSION (OPT_P_INSTANCE);
2302 +      option_iroute_ipv6 (options, p[1], msglevel);
2303 +    }
2304    else if (streq (p[0], "ifconfig-push") && p[1] && p[2])
2305      {
2306        in_addr_t local, remote_netmask;
2307 @@ -5114,6 +5346,43 @@
2308           goto err;
2309         }
2310      }
2311 +  else if (streq (p[0], "ifconfig-ipv6-push") && p[1] )
2312 +    {
2313 +      struct in6_addr local, remote;
2314 +      unsigned int netbits;
2315 +
2316 +      VERIFY_PERMISSION (OPT_P_INSTANCE);
2317 +
2318 +      if ( ! get_ipv6_addr( p[1], &local, &netbits, NULL, msglevel ) )
2319 +       {
2320 +         msg (msglevel, "cannot parse --ifconfig-ipv6-push addresses");
2321 +         goto err;
2322 +       }
2323 +
2324 +      if ( p[2] )
2325 +       {
2326 +         if ( !get_ipv6_addr( p[2], &remote, NULL, NULL, msglevel ) )
2327 +           {
2328 +             msg( msglevel, "cannot parse --ifconfig-ipv6-push addresses");
2329 +             goto err;
2330 +           }
2331 +       }
2332 +      else
2333 +       {
2334 +         if ( ! options->ifconfig_ipv6_local ||
2335 +              ! get_ipv6_addr( options->ifconfig_ipv6_local, &remote, 
2336 +                               NULL, NULL, msglevel ) )
2337 +           {
2338 +             msg( msglevel, "second argument to --ifconfig-ipv6-push missing and no global --ifconfig-ipv6 address set");
2339 +             goto err;
2340 +           }
2341 +       }
2342 +
2343 +      options->push_ifconfig_ipv6_defined = true;
2344 +      options->push_ifconfig_ipv6_local = local;
2345 +      options->push_ifconfig_ipv6_netbits = netbits;
2346 +      options->push_ifconfig_ipv6_remote = remote;
2347 +    }
2348    else if (streq (p[0], "disable"))
2349      {
2350        VERIFY_PERMISSION (OPT_P_INSTANCE);
2351 diff -durN openvpn-2.2.2.orig/options.h openvpn-2.2.2/options.h
2352 --- openvpn-2.2.2.orig/options.h        2011-12-13 17:58:56.000000000 +0100
2353 +++ openvpn-2.2.2/options.h     2012-06-01 10:44:37.000000000 +0200
2354 @@ -205,6 +205,9 @@
2355    int topology; /* one of the TOP_x values from proto.h */
2356    const char *ifconfig_local;
2357    const char *ifconfig_remote_netmask;
2358 +  const char *ifconfig_ipv6_local;
2359 +  int         ifconfig_ipv6_netbits;
2360 +  const char *ifconfig_ipv6_remote;
2361    bool ifconfig_noexec;
2362    bool ifconfig_nowarn;
2363  #ifdef HAVE_GETTIMEOFDAY
2364 @@ -326,6 +329,7 @@
2365    bool route_delay_defined;
2366    int max_routes;
2367    struct route_option_list *routes;
2368 +  struct route_ipv6_option_list *routes_ipv6;                  /* IPv6 */
2369    bool route_nopull;
2370    bool route_gateway_via_dhcp;
2371    bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
2372 @@ -363,6 +367,9 @@
2373    bool server_defined;
2374    in_addr_t server_network;
2375    in_addr_t server_netmask;
2376 +  bool server_ipv6_defined;                            /* IPv6 */
2377 +  struct in6_addr server_network_ipv6;                 /* IPv6 */
2378 +  unsigned int    server_netbits_ipv6;                 /* IPv6 */
2379  
2380  # define SF_NOPOOL (1<<0)
2381  # define SF_TCP_NODELAY_HELPER (1<<1)
2382 @@ -384,6 +391,11 @@
2383    in_addr_t ifconfig_pool_netmask;
2384    const char *ifconfig_pool_persist_filename;
2385    int ifconfig_pool_persist_refresh_freq;
2386 +
2387 +  bool   ifconfig_ipv6_pool_defined;                   /* IPv6 */
2388 +  struct in6_addr ifconfig_ipv6_pool_base;             /* IPv6 */
2389 +  int    ifconfig_ipv6_pool_netbits;                   /* IPv6 */
2390 +
2391    int real_hash_size;
2392    int virtual_hash_size;
2393    const char *client_connect_script;
2394 @@ -395,12 +407,17 @@
2395    int n_bcast_buf;
2396    int tcp_queue_limit;
2397    struct iroute *iroutes;
2398 +  struct iroute_ipv6 *iroutes_ipv6;                    /* IPv6 */
2399    bool push_ifconfig_defined;
2400    in_addr_t push_ifconfig_local;
2401    in_addr_t push_ifconfig_remote_netmask;
2402    bool push_ifconfig_constraint_defined;
2403    in_addr_t push_ifconfig_constraint_network;
2404    in_addr_t push_ifconfig_constraint_netmask;
2405 +  bool            push_ifconfig_ipv6_defined;          /* IPv6 */
2406 +  struct in6_addr push_ifconfig_ipv6_local;            /* IPv6 */
2407 +  int            push_ifconfig_ipv6_netbits;           /* IPv6 */
2408 +  struct in6_addr push_ifconfig_ipv6_remote;           /* IPv6 */
2409    bool enable_c2c;
2410    bool duplicate_cn;
2411    int cf_max;
2412 @@ -723,6 +740,10 @@
2413                             unsigned int *option_types_found,
2414                             struct env_set *es);
2415  
2416 +bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
2417 +                   unsigned int * netbits, char ** printable_ipv6, 
2418 +                   int msglevel );
2419 +
2420  /*
2421   * inline functions
2422   */
2423 diff -durN openvpn-2.2.2.orig/options.h~ openvpn-2.2.2/options.h~
2424 --- openvpn-2.2.2.orig/options.h~       1970-01-01 01:00:00.000000000 +0100
2425 +++ openvpn-2.2.2/options.h~    2012-06-01 10:44:29.000000000 +0200
2426 @@ -0,0 +1,780 @@
2427 +/*
2428 + *  OpenVPN -- An application to securely tunnel IP networks
2429 + *             over a single UDP port, with support for SSL/TLS-based
2430 + *             session authentication and key exchange,
2431 + *             packet encryption, packet authentication, and
2432 + *             packet compression.
2433 + *
2434 + *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
2435 + *
2436 + *  This program is free software; you can redistribute it and/or modify
2437 + *  it under the terms of the GNU General Public License version 2
2438 + *  as published by the Free Software Foundation.
2439 + *
2440 + *  This program is distributed in the hope that it will be useful,
2441 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2442 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2443 + *  GNU General Public License for more details.
2444 + *
2445 + *  You should have received a copy of the GNU General Public License
2446 + *  along with this program (see the file COPYING included with this
2447 + *  distribution); if not, write to the Free Software Foundation, Inc.,
2448 + *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2449 + */
2450 +
2451 +/*
2452 + * 2004-01-28: Added Socks5 proxy support
2453 + *   (Christof Meerwald, http://cmeerw.org)
2454 + */
2455 +
2456 +#ifndef OPTIONS_H
2457 +#define OPTIONS_H
2458 +
2459 +#include "basic.h"
2460 +#include "common.h"
2461 +#include "mtu.h"
2462 +#include "route.h"
2463 +#include "tun.h"
2464 +#include "socket.h"
2465 +#include "plugin.h"
2466 +#include "manage.h"
2467 +#include "proxy.h"
2468 +#include "lzo.h"
2469 +#include "pushlist.h"
2470 +
2471 +/*
2472 + * Maximum number of parameters associated with an option,
2473 + * including the option name itself.
2474 + */
2475 +#define MAX_PARMS 16
2476 +
2477 +/*
2478 + * Max size of options line and parameter.
2479 + */
2480 +#define OPTION_PARM_SIZE 256
2481 +#define OPTION_LINE_SIZE 256
2482 +
2483 +extern const char title_string[];
2484 +
2485 +#if P2MP
2486 +
2487 +/* certain options are saved before --pull modifications are applied */
2488 +struct options_pre_pull
2489 +{
2490 +  bool tuntap_options_defined;
2491 +  struct tuntap_options tuntap_options;
2492 +
2493 +  bool routes_defined;
2494 +  struct route_option_list *routes;
2495 +
2496 +  int foreign_option_index;
2497 +};
2498 +
2499 +#endif
2500 +
2501 +struct connection_entry
2502 +{
2503 +  int proto;
2504 +  int local_port;
2505 +  bool local_port_defined;
2506 +  int remote_port;
2507 +  bool port_option_used;
2508 +  const char *local;
2509 +  const char *remote;
2510 +  bool remote_float;
2511 +  bool bind_defined;
2512 +  bool bind_local;
2513 +  int connect_retry_seconds;
2514 +  bool connect_retry_defined;
2515 +  int connect_retry_max;
2516 +  int connect_timeout;
2517 +  bool connect_timeout_defined;
2518 +#ifdef ENABLE_HTTP_PROXY
2519 +  struct http_proxy_options *http_proxy_options;
2520 +#endif  
2521 +#ifdef ENABLE_SOCKS
2522 +  const char *socks_proxy_server;
2523 +  int socks_proxy_port;
2524 +  const char *socks_proxy_authfile;
2525 +  bool socks_proxy_retry;
2526 +#endif
2527 +
2528 +# define CE_DISABLED (1<<0)
2529 +#if HTTP_PROXY_FALLBACK
2530 +# define CE_HTTP_PROXY_FALLBACK (1<<1)
2531 +  time_t ce_http_proxy_fallback_timestamp; /* time when fallback http_proxy_options was last updated */
2532 +#endif
2533 +
2534 +  unsigned int flags;
2535 +};
2536 +
2537 +struct remote_entry
2538 +{
2539 +  const char *remote;
2540 +  int remote_port;
2541 +  int proto;
2542 +};
2543 +
2544 +#ifdef ENABLE_CONNECTION
2545 +
2546 +#define CONNECTION_LIST_SIZE 64
2547 +
2548 +struct connection_list
2549 +{
2550 +  int len;
2551 +  int current;
2552 +  int n_cycles;
2553 +  bool no_advance;
2554 +  struct connection_entry *array[CONNECTION_LIST_SIZE];
2555 +};
2556 +
2557 +struct remote_list
2558 +{
2559 +  int len;
2560 +  struct remote_entry *array[CONNECTION_LIST_SIZE];
2561 +};
2562 +
2563 +#endif
2564 +
2565 +#if HTTP_PROXY_FALLBACK
2566 +struct hpo_store
2567 +{
2568 +  struct http_proxy_options hpo;
2569 +  char server[80];
2570 +};
2571 +#endif
2572 +
2573 +/* Command line options */
2574 +struct options
2575 +{
2576 +  struct gc_arena gc;
2577 +  bool gc_owned;
2578 +
2579 +  /* first config file */
2580 +  const char *config;
2581 +
2582 +  /* major mode */
2583 +# define MODE_POINT_TO_POINT 0
2584 +# define MODE_SERVER         1
2585 +  int mode;
2586 +
2587 +  /* enable forward compatibility for post-2.1 features */
2588 +  bool forward_compatible;
2589 +
2590 +  /* persist parms */
2591 +  bool persist_config;
2592 +  int persist_mode;
2593 +
2594 +#ifdef USE_CRYPTO
2595 +  const char *key_pass_file;
2596 +  bool show_ciphers;
2597 +  bool show_digests;
2598 +  bool show_engines;
2599 +#ifdef USE_SSL
2600 +  bool show_tls_ciphers;
2601 +#endif
2602 +  bool genkey;
2603 +#endif
2604 +
2605 +  /* Networking parms */
2606 +  struct connection_entry ce;
2607 +
2608 +#ifdef ENABLE_CONNECTION
2609 +  char *remote_ip_hint;
2610 +  struct connection_list *connection_list;
2611 +  struct remote_list *remote_list;
2612 +  bool force_connection_list;
2613 +#endif
2614 +
2615 +#ifdef GENERAL_PROXY_SUPPORT
2616 +  struct auto_proxy_info *auto_proxy_info;
2617 +#endif
2618 +
2619 +#if HTTP_PROXY_FALLBACK
2620 +  bool http_proxy_fallback;
2621 +  struct http_proxy_options *http_proxy_override;
2622 +  struct hpo_store *hpo_store; /* used to store dynamic proxy info given by management interface */
2623 +#endif
2624 +
2625 +  bool remote_random;
2626 +  const char *ipchange;
2627 +  const char *dev;
2628 +  const char *dev_type;
2629 +  const char *dev_node;
2630 +  const char *lladdr;
2631 +  int topology; /* one of the TOP_x values from proto.h */
2632 +  const char *ifconfig_local;
2633 +  const char *ifconfig_remote_netmask;
2634 +  const char *ifconfig_ipv6_local;
2635 +  int         ifconfig_ipv6_netbits;
2636 +  const char *ifconfig_ipv6_remote;
2637 +  bool ifconfig_noexec;
2638 +  bool ifconfig_nowarn;
2639 +#ifdef HAVE_GETTIMEOFDAY
2640 +  int shaper;
2641 +#endif
2642 +  int tun_mtu;           /* MTU of tun device */
2643 +  int tun_mtu_extra;
2644 +  bool tun_mtu_extra_defined;
2645 +  int link_mtu;          /* MTU of device over which tunnel packets pass via TCP/UDP */
2646 +  bool tun_mtu_defined;  /* true if user overriding parm with command line option */
2647 +  bool link_mtu_defined; /* true if user overriding parm with command line option */
2648 +
2649 +  int proto_force;
2650 +
2651 +  /* Advanced MTU negotiation and datagram fragmentation options */
2652 +  int mtu_discover_type; /* used if OS supports setting Path MTU discovery options on socket */
2653 +
2654 +#ifdef ENABLE_OCC
2655 +  bool mtu_test;
2656 +#endif
2657 +
2658 +  int fragment;                 /* internal fragmentation size */
2659 +
2660 +  bool mlock;
2661 +
2662 +  int keepalive_ping;           /* a proxy for ping/ping-restart */
2663 +  int keepalive_timeout;
2664 +
2665 +  int inactivity_timeout;       /* --inactive */
2666 +  int inactivity_minimum_bytes;
2667 +
2668 +  int ping_send_timeout;        /* Send a TCP/UDP ping to remote every n seconds */
2669 +  int ping_rec_timeout;         /* Expect a TCP/UDP ping from remote at least once every n seconds */
2670 +  bool ping_timer_remote;       /* Run ping timer only if we have a remote address */
2671 +  bool tun_ipv6;                /* Build tun dev that supports IPv6 */
2672 +
2673 +# define PING_UNDEF   0
2674 +# define PING_EXIT    1
2675 +# define PING_RESTART 2
2676 +  int ping_rec_timeout_action;  /* What action to take on ping_rec_timeout (exit or restart)? */
2677 +
2678 +#ifdef ENABLE_OCC
2679 +  int explicit_exit_notification;  /* Explicitly tell peer when we are exiting via OCC_EXIT message */
2680 +#endif
2681 +
2682 +  bool persist_tun;             /* Don't close/reopen TUN/TAP dev on SIGUSR1 or PING_RESTART */
2683 +  bool persist_local_ip;        /* Don't re-resolve local address on SIGUSR1 or PING_RESTART */
2684 +  bool persist_remote_ip;       /* Don't re-resolve remote address on SIGUSR1 or PING_RESTART */
2685 +  bool persist_key;             /* Don't re-read key files on SIGUSR1 or PING_RESTART */
2686 +
2687 +  int mssfix;                   /* Upper bound on TCP MSS */
2688 +  bool mssfix_default;          /* true if --mssfix was supplied without a parameter */
2689 +
2690 +#if PASSTOS_CAPABILITY
2691 +  bool passtos;                  
2692 +#endif
2693 +
2694 +  int resolve_retry_seconds;    /* If hostname resolve fails, retry for n seconds */
2695 +
2696 +  struct tuntap_options tuntap_options;
2697 +
2698 +  /* Misc parms */
2699 +  const char *username;
2700 +  const char *groupname;
2701 +  const char *chroot_dir;
2702 +  const char *cd_dir;
2703 +#ifdef HAVE_SETCON
2704 +  char *selinux_context;
2705 +#endif
2706 +  const char *writepid;
2707 +  const char *up_script;
2708 +  const char *down_script;
2709 +  bool down_pre;
2710 +  bool up_delay;
2711 +  bool up_restart;
2712 +  bool daemon;
2713 +
2714 +  int remap_sigusr1;
2715 +
2716 +  /* inetd modes defined in socket.h */
2717 +  int inetd;
2718 +
2719 +  bool log;
2720 +  bool suppress_timestamps;
2721 +  int nice;
2722 +  int verbosity;
2723 +  int mute;
2724 +
2725 +#ifdef ENABLE_DEBUG
2726 +  int gremlin;
2727 +#endif
2728 +
2729 +  const char *status_file;
2730 +  int status_file_version;
2731 +  int status_file_update_freq;
2732 +
2733 +  /* optimize TUN/TAP/UDP writes */
2734 +  bool fast_io;
2735 +
2736 +#ifdef USE_LZO
2737 +  /* LZO_x flags from lzo.h */
2738 +  unsigned int lzo;
2739 +#endif
2740 +
2741 +  /* buffer sizes */
2742 +  int rcvbuf;
2743 +  int sndbuf;
2744 +
2745 +  /* socket flags */
2746 +  unsigned int sockflags;
2747 +
2748 +  /* route management */
2749 +  const char *route_script;
2750 +  const char *route_default_gateway;
2751 +  int route_default_metric;
2752 +  bool route_noexec;
2753 +  int route_delay;
2754 +  int route_delay_window;
2755 +  bool route_delay_defined;
2756 +  int max_routes;
2757 +  struct route_option_list *routes;
2758 +  struct route_ipv6_option_list *routes_ipv6;                  /* IPv6 */
2759 +  bool route_nopull;
2760 +  bool route_gateway_via_dhcp;
2761 +  bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
2762 +
2763 +#ifdef ENABLE_OCC
2764 +  /* Enable options consistency check between peers */
2765 +  bool occ;
2766 +#endif
2767 +
2768 +#ifdef ENABLE_MANAGEMENT
2769 +  const char *management_addr;
2770 +  int management_port;
2771 +  const char *management_user_pass;
2772 +  int management_log_history_cache;
2773 +  int management_echo_buffer_size;
2774 +  int management_state_buffer_size;
2775 +  const char *management_write_peer_info_file;
2776 +
2777 +  const char *management_client_user;
2778 +  const char *management_client_group;
2779 +
2780 +  /* Mask of MF_ values of manage.h */
2781 +  unsigned int management_flags;
2782 +#endif
2783 +
2784 +#ifdef ENABLE_PLUGIN
2785 +  struct plugin_option_list *plugin_list;
2786 +#endif
2787 +
2788 +  const char *tmp_dir;
2789 +
2790 +#if P2MP
2791 +
2792 +#if P2MP_SERVER
2793 +  bool server_defined;
2794 +  in_addr_t server_network;
2795 +  in_addr_t server_netmask;
2796 +  bool server_ipv6_defined;                            /* IPv6 */
2797 +  struct in6_addr server_network_ipv6;                 /* IPv6 */
2798 +  unsigned int    server_netbits_ipv6;                 /* IPv6 */
2799 +
2800 +# define SF_NOPOOL (1<<0)
2801 +# define SF_TCP_NODELAY_HELPER (1<<1)
2802 +# define SF_NO_PUSH_ROUTE_GATEWAY (1<<2)
2803 +  unsigned int server_flags;
2804 +
2805 +  bool server_bridge_proxy_dhcp;
2806 +
2807 +  bool server_bridge_defined;
2808 +  in_addr_t server_bridge_ip;
2809 +  in_addr_t server_bridge_netmask;
2810 +  in_addr_t server_bridge_pool_start;
2811 +  in_addr_t server_bridge_pool_end;
2812 +
2813 +  struct push_list push_list;
2814 +  bool ifconfig_pool_defined;
2815 +  in_addr_t ifconfig_pool_start;
2816 +  in_addr_t ifconfig_pool_end;
2817 +  in_addr_t ifconfig_pool_netmask;
2818 +  const char *ifconfig_pool_persist_filename;
2819 +  int ifconfig_pool_persist_refresh_freq;
2820 +
2821 +  bool   ifconfig_ipv6_pool_defined;                   /* IPv6 */
2822 +  struct in6_addr ifconfig_ipv6_pool_base;             /* IPv6 */
2823 +  int    ifconfig_ipv6_pool_netbits;                   /* IPv6 */
2824 +
2825 +  int real_hash_size;
2826 +  int virtual_hash_size;
2827 +  const char *client_connect_script;
2828 +  const char *client_disconnect_script;
2829 +  const char *learn_address_script;
2830 +  const char *client_config_dir;
2831 +  bool ccd_exclusive;
2832 +  bool disable;
2833 +  int n_bcast_buf;
2834 +  int tcp_queue_limit;
2835 +  struct iroute *iroutes;
2836 +  struct iroute_ipv6 *iroutes_ipv6;                    /* IPv6 */
2837 +  bool push_ifconfig_defined;
2838 +  in_addr_t push_ifconfig_local;
2839 +  in_addr_t push_ifconfig_remote_netmask;
2840 +  bool push_ifconfig_constraint_defined;
2841 +  in_addr_t push_ifconfig_constraint_network;
2842 +  in_addr_t push_ifconfig_constraint_netmask;
2843 +  bool            push_ifconfig_ipv6_defined;          /* IPv6 */
2844 +  struct in6_addr push_ifconfig_ipv6_local;            /* IPv6 */
2845 +  int            push_ifconfig_ipv6_netbits;           /* IPv6 */
2846 +  struct in6_addr push_ifconfig_ipv6_remote;           /* IPv6 */
2847 +  bool enable_c2c;
2848 +  bool duplicate_cn;
2849 +  int cf_max;
2850 +  int cf_per;
2851 +  int max_clients;
2852 +  int max_routes_per_client;
2853 +
2854 +  const char *auth_user_pass_verify_script;
2855 +  bool auth_user_pass_verify_script_via_file;
2856 +  unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */
2857 +#if PORT_SHARE
2858 +  char *port_share_host;
2859 +  int port_share_port;
2860 +#endif
2861 +#endif
2862 +
2863 +  bool client;
2864 +  bool pull; /* client pull of config options from server */
2865 +  int push_continuation;
2866 +  const char *auth_user_pass_file;
2867 +  struct options_pre_pull *pre_pull;
2868 +
2869 +  int server_poll_timeout;
2870 +
2871 +  int scheduled_exit_interval;
2872 +
2873 +#endif
2874 +
2875 +#ifdef USE_CRYPTO
2876 +  /* Cipher parms */
2877 +  const char *shared_secret_file;
2878 +#if ENABLE_INLINE_FILES
2879 +  const char *shared_secret_file_inline;
2880 +#endif
2881 +  int key_direction;
2882 +  bool ciphername_defined;
2883 +  const char *ciphername;
2884 +  bool authname_defined;
2885 +  const char *authname;
2886 +  int keysize;
2887 +  const char *prng_hash;
2888 +  int prng_nonce_secret_len;
2889 +  const char *engine;
2890 +  bool replay;
2891 +  bool mute_replay_warnings;
2892 +  int replay_window;
2893 +  int replay_time;
2894 +  const char *packet_id_file;
2895 +  bool use_iv;
2896 +  bool test_crypto;
2897 +
2898 +#ifdef USE_SSL
2899 +  /* TLS (control channel) parms */
2900 +  bool tls_server;
2901 +  bool tls_client;
2902 +  const char *ca_file;
2903 +  const char *ca_path;
2904 +  const char *dh_file;
2905 +  const char *cert_file;
2906 +  const char *priv_key_file;
2907 +  const char *pkcs12_file;
2908 +  const char *cipher_list;
2909 +  const char *tls_verify;
2910 +  const char *tls_export_cert;
2911 +  const char *tls_remote;
2912 +  const char *crl_file;
2913 +
2914 +#if ENABLE_INLINE_FILES
2915 +  const char *ca_file_inline;
2916 +  const char *cert_file_inline;
2917 +  char *priv_key_file_inline;
2918 +  const char *dh_file_inline;
2919 +  const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */
2920 +#endif
2921 +
2922 +  int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */
2923 +  unsigned remote_cert_ku[MAX_PARMS];
2924 +  const char *remote_cert_eku;
2925 +
2926 +#ifdef ENABLE_PKCS11
2927 +  const char *pkcs11_providers[MAX_PARMS];
2928 +  unsigned pkcs11_private_mode[MAX_PARMS];
2929 +  bool pkcs11_protected_authentication[MAX_PARMS];
2930 +  bool pkcs11_cert_private[MAX_PARMS];
2931 +  int pkcs11_pin_cache_period;
2932 +  const char *pkcs11_id;
2933 +  bool pkcs11_id_management;
2934 +#endif
2935 +
2936 +#ifdef WIN32
2937 +  const char *cryptoapi_cert;
2938 +#endif
2939 +
2940 +  /* data channel key exchange method */
2941 +  int key_method;
2942 +
2943 +  /* Per-packet timeout on control channel */
2944 +  int tls_timeout;
2945 +
2946 +  /* Data channel key renegotiation parameters */
2947 +  int renegotiate_bytes;
2948 +  int renegotiate_packets;
2949 +  int renegotiate_seconds;
2950 +
2951 +  /* Data channel key handshake must finalize
2952 +     within n seconds of handshake initiation. */
2953 +  int handshake_window;
2954 +
2955 +#ifdef ENABLE_X509ALTUSERNAME
2956 +  /* Field used to be the username in X509 cert. */
2957 +  char *x509_username_field;
2958 +#endif
2959 +
2960 +  /* Old key allowed to live n seconds after new key goes active */
2961 +  int transition_window;
2962 +
2963 +  /* Special authentication MAC for TLS control channel */
2964 +  const char *tls_auth_file;           /* shared secret */
2965 +#if ENABLE_INLINE_FILES
2966 +  const char *tls_auth_file_inline;
2967 +#endif
2968 +
2969 +  /* Allow only one session */
2970 +  bool single_session;
2971 +
2972 +#ifdef ENABLE_PUSH_PEER_INFO
2973 +  bool push_peer_info;
2974 +#endif
2975 +
2976 +  bool tls_exit;
2977 +
2978 +#endif /* USE_SSL */
2979 +#endif /* USE_CRYPTO */
2980 +
2981 +  /* special state parms */
2982 +  int foreign_option_index;
2983 +
2984 +#ifdef WIN32
2985 +  const char *exit_event_name;
2986 +  bool exit_event_initial_state;
2987 +  bool show_net_up;
2988 +  int route_method;
2989 +#endif
2990 +};
2991 +
2992 +#define streq(x, y) (!strcmp((x), (y)))
2993 +
2994 +/*
2995 + * Option classes.
2996 + */
2997 +#define OPT_P_GENERAL         (1<<0)
2998 +#define OPT_P_UP              (1<<1)
2999 +#define OPT_P_ROUTE           (1<<2)
3000 +#define OPT_P_IPWIN32         (1<<3)
3001 +#define OPT_P_SCRIPT          (1<<4)
3002 +#define OPT_P_SETENV          (1<<5)
3003 +#define OPT_P_SHAPER          (1<<6)
3004 +#define OPT_P_TIMER           (1<<7)
3005 +#define OPT_P_PERSIST         (1<<8)
3006 +#define OPT_P_PERSIST_IP      (1<<9)
3007 +#define OPT_P_COMP            (1<<10) /* TODO */
3008 +#define OPT_P_MESSAGES        (1<<11)
3009 +#define OPT_P_CRYPTO          (1<<12) /* TODO */
3010 +#define OPT_P_TLS_PARMS       (1<<13) /* TODO */
3011 +#define OPT_P_MTU             (1<<14) /* TODO */
3012 +#define OPT_P_NICE            (1<<15)
3013 +#define OPT_P_PUSH            (1<<16)
3014 +#define OPT_P_INSTANCE        (1<<17)
3015 +#define OPT_P_CONFIG          (1<<18)
3016 +#define OPT_P_EXPLICIT_NOTIFY (1<<19)
3017 +#define OPT_P_ECHO            (1<<20)
3018 +#define OPT_P_INHERIT         (1<<21)
3019 +#define OPT_P_ROUTE_EXTRAS    (1<<22)
3020 +#define OPT_P_PULL_MODE       (1<<23)
3021 +#define OPT_P_PLUGIN          (1<<24)
3022 +#define OPT_P_SOCKBUF         (1<<25)
3023 +#define OPT_P_SOCKFLAGS       (1<<26)
3024 +#define OPT_P_CONNECTION      (1<<27)
3025 +
3026 +#define OPT_P_DEFAULT   (~(OPT_P_INSTANCE|OPT_P_PULL_MODE))
3027 +
3028 +#if P2MP
3029 +#define PULL_DEFINED(opt) ((opt)->pull)
3030 +#if P2MP_SERVER
3031 +#define PUSH_DEFINED(opt) ((opt)->push_list)
3032 +#endif
3033 +#endif
3034 +
3035 +#ifndef PULL_DEFINED
3036 +#define PULL_DEFINED(opt) (false)
3037 +#endif
3038 +
3039 +#ifndef PUSH_DEFINED
3040 +#define PUSH_DEFINED(opt) (false)
3041 +#endif
3042 +
3043 +#ifdef WIN32
3044 +#define ROUTE_OPTION_FLAGS(o) ((o)->route_method & ROUTE_METHOD_MASK)
3045 +#else
3046 +#define ROUTE_OPTION_FLAGS(o) (0)
3047 +#endif
3048 +
3049 +#ifdef HAVE_GETTIMEOFDAY
3050 +#define SHAPER_DEFINED(opt) ((opt)->shaper)
3051 +#else
3052 +#define SHAPER_DEFINED(opt) (false)
3053 +#endif
3054 +
3055 +#ifdef ENABLE_PLUGIN
3056 +#define PLUGIN_OPTION_LIST(opt) ((opt)->plugin_list)
3057 +#else
3058 +#define PLUGIN_OPTION_LIST(opt) (NULL)
3059 +#endif
3060 +
3061 +#ifdef MANAGEMENT_DEF_AUTH
3062 +#define MAN_CLIENT_AUTH_ENABLED(opt) ((opt)->management_flags & MF_CLIENT_AUTH)
3063 +#else
3064 +#define MAN_CLIENT_AUTH_ENABLED(opt) (false)
3065 +#endif
3066 +
3067 +void parse_argv (struct options *options,
3068 +                const int argc,
3069 +                char *argv[],
3070 +                const int msglevel,
3071 +                const unsigned int permission_mask,
3072 +                unsigned int *option_types_found,
3073 +                struct env_set *es);
3074 +
3075 +void notnull (const char *arg, const char *description);
3076 +
3077 +void usage_small (void);
3078 +
3079 +void init_options (struct options *o, const bool init_gc);
3080 +void uninit_options (struct options *o);
3081 +
3082 +void setenv_settings (struct env_set *es, const struct options *o);
3083 +void show_settings (const struct options *o);
3084 +
3085 +bool string_defined_equal (const char *s1, const char *s2);
3086 +
3087 +#ifdef ENABLE_OCC
3088 +
3089 +const char *options_string_version (const char* s, struct gc_arena *gc);
3090 +
3091 +char *options_string (const struct options *o,
3092 +                     const struct frame *frame,
3093 +                     struct tuntap *tt,
3094 +                     bool remote,
3095 +                     struct gc_arena *gc);
3096 +
3097 +bool options_cmp_equal_safe (char *actual, const char *expected, size_t actual_n);
3098 +void options_warning_safe (char *actual, const char *expected, size_t actual_n);
3099 +bool options_cmp_equal (char *actual, const char *expected);
3100 +void options_warning (char *actual, const char *expected);
3101 +
3102 +#endif
3103 +
3104 +void options_postprocess (struct options *options);
3105 +
3106 +void pre_pull_save (struct options *o);
3107 +void pre_pull_restore (struct options *o);
3108 +
3109 +bool apply_push_options (struct options *options,
3110 +                        struct buffer *buf,
3111 +                        unsigned int permission_mask,
3112 +                        unsigned int *option_types_found,
3113 +                        struct env_set *es);
3114 +
3115 +bool is_persist_option (const struct options *o);
3116 +bool is_stateful_restart (const struct options *o);
3117 +
3118 +void options_detach (struct options *o);
3119 +
3120 +void options_server_import (struct options *o,
3121 +                           const char *filename,
3122 +                           int msglevel,
3123 +                           unsigned int permission_mask,
3124 +                           unsigned int *option_types_found,
3125 +                           struct env_set *es);
3126 +
3127 +void pre_pull_default (struct options *o);
3128 +
3129 +void rol_check_alloc (struct options *options);
3130 +
3131 +int parse_line (const char *line,
3132 +               char *p[],
3133 +               const int n,
3134 +               const char *file,
3135 +               const int line_num,
3136 +               int msglevel,
3137 +               struct gc_arena *gc);
3138 +
3139 +/*
3140 + * parse/print topology coding
3141 + */
3142 +
3143 +int parse_topology (const char *str, const int msglevel);
3144 +const char *print_topology (const int topology);
3145 +
3146 +/*
3147 + * Manage auth-retry variable
3148 + */
3149 +
3150 +#if P2MP
3151 +
3152 +#define AR_NONE       0
3153 +#define AR_INTERACT   1
3154 +#define AR_NOINTERACT 2
3155 +
3156 +int auth_retry_get (void);
3157 +bool auth_retry_set (const int msglevel, const char *option);
3158 +const char *auth_retry_print (void);
3159 +
3160 +#endif
3161 +
3162 +void options_string_import (struct options *options,
3163 +                           const char *config,
3164 +                           const int msglevel,
3165 +                           const unsigned int permission_mask,
3166 +                           unsigned int *option_types_found,
3167 +                           struct env_set *es);
3168 +
3169 +bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
3170 +                   unsigned int * netbits, char ** printable_ipv6, 
3171 +                   int msglevel );
3172 +
3173 +/*
3174 + * inline functions
3175 + */
3176 +static inline bool
3177 +connection_list_defined (const struct options *o)
3178 +{
3179 +#ifdef ENABLE_CONNECTION
3180 +  return o->connection_list != NULL;
3181 +#else
3182 +  return false;
3183 +#endif
3184 +}
3185 +
3186 +static inline void
3187 +connection_list_set_no_advance (struct options *o)
3188 +{
3189 +#ifdef ENABLE_CONNECTION
3190 +  if (o->connection_list)
3191 +    o->connection_list->no_advance = true;
3192 +#endif
3193 +}
3194 +
3195 +#if HTTP_PROXY_FALLBACK
3196 +
3197 +struct http_proxy_options *
3198 +parse_http_proxy_fallback (struct context *c,
3199 +                          const char *server,
3200 +                          const char *port,
3201 +                          const char *flags,
3202 +                          const int msglevel);
3203 +
3204 +#endif /* HTTP_PROXY_FALLBACK */
3205 +
3206 +#endif
3207 diff -durN openvpn-2.2.2.orig/pool.c openvpn-2.2.2/pool.c
3208 --- openvpn-2.2.2.orig/pool.c   2011-12-13 17:58:56.000000000 +0100
3209 +++ openvpn-2.2.2/pool.c        2012-06-01 10:40:28.000000000 +0200
3210 @@ -132,7 +132,10 @@
3211  }
3212  
3213  struct ifconfig_pool *
3214 -ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn)
3215 +ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, 
3216 +                   const bool duplicate_cn,
3217 +                   const bool ipv6_pool, const struct in6_addr ipv6_base, 
3218 +                   const int ipv6_netbits )
3219  {
3220    struct gc_arena gc = gc_new ();
3221    struct ifconfig_pool *pool = NULL;
3222 @@ -157,11 +160,31 @@
3223        ASSERT (0);
3224      }
3225  
3226 +  /* IPv6 pools are always "INDIV" type */
3227 +  pool->ipv6 = ipv6_pool;
3228 +
3229 +  if ( pool->ipv6 )
3230 +    {
3231 +      pool->base_ipv6 = ipv6_base;
3232 +      pool->size_ipv6 = ipv6_netbits>96? ( 1<<(128-ipv6_netbits) ) 
3233 +                                      : IFCONFIG_POOL_MAX;
3234 +
3235 +      msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s",
3236 +                           pool->size, pool->size_ipv6, ipv6_netbits,
3237 +                           print_in6_addr( pool->base_ipv6, 0, &gc ));
3238 +
3239 +      /* the current code is very simple and assumes that the IPv6
3240 +       * pool is at least as big as the IPv4 pool, and we don't need
3241 +       * to do separate math etc. for IPv6
3242 +       */
3243 +      ASSERT( pool->size < pool->size_ipv6 );
3244 +    }
3245 +
3246    ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size);
3247  
3248 -  msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d",
3249 +  msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d",
3250         print_in_addr_t (pool->base, 0, &gc),
3251 -       pool->size);
3252 +       pool->size, pool->ipv6 );
3253  
3254    gc_free (&gc);
3255    return pool;
3256 @@ -181,7 +204,7 @@
3257  }
3258  
3259  ifconfig_pool_handle
3260 -ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name)
3261 +ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name)
3262  {
3263    int i;
3264  
3265 @@ -214,6 +237,12 @@
3266         default:
3267           ASSERT (0);
3268         }
3269 +
3270 +      /* IPv6 pools are always INDIV (--linear) */
3271 +      if ( pool->ipv6 && remote_ipv6 )
3272 +       {
3273 +         *remote_ipv6 = add_in6_addr( pool->base_ipv6, i );
3274 +       }
3275      }
3276    return i;
3277  }
3278 @@ -288,6 +317,19 @@
3279    return ret;
3280  }
3281  
3282 +static struct in6_addr
3283 +ifconfig_pool_handle_to_ipv6_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
3284 +{
3285 +  struct in6_addr ret = in6addr_any;
3286 +
3287 +  /* IPv6 pools are always INDIV (--linear) */
3288 +  if (hand >= 0 && hand < pool->size_ipv6 )
3289 +    {
3290 +      ret = add_in6_addr( pool->base_ipv6, hand );
3291 +    }
3292 +  return ret;
3293 +}
3294 +
3295  static void
3296  ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed)
3297  {
3298 @@ -317,9 +359,20 @@
3299           if (e->common_name)
3300             {
3301               const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i);
3302 -             status_printf (out, "%s,%s",
3303 -                            e->common_name,
3304 -                            print_in_addr_t (ip, 0, &gc));
3305 +             if ( pool->ipv6 )
3306 +               {
3307 +                 struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base (pool, i);
3308 +                 status_printf (out, "%s,%s,%s",
3309 +                                e->common_name,
3310 +                                print_in_addr_t (ip, 0, &gc),
3311 +                                print_in6_addr (ip6, 0, &gc));
3312 +               }
3313 +             else
3314 +               {
3315 +                 status_printf (out, "%s,%s",
3316 +                                e->common_name,
3317 +                                print_in_addr_t (ip, 0, &gc));
3318 +               }
3319             }
3320         }
3321        gc_free (&gc);
3322 @@ -409,6 +462,9 @@
3323               int c = *BSTR(&in);
3324               if (c == '#' || c == ';')
3325                 continue;
3326 +             msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6",
3327 +                               BSTR(&in) );
3328 +
3329               if (buf_parse (&in, ',', cn_buf, buf_size)
3330                   && buf_parse (&in, ',', ip_buf, buf_size))
3331                 {
3332 @@ -416,6 +472,7 @@
3333                   const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
3334                   if (succeeded)
3335                     {
3336 +                     msg( M_INFO, "succeeded -> ifconfig_pool_set()");
3337                       ifconfig_pool_set (pool, cn_buf, addr, persist->fixed);
3338                     }
3339                 }
3340 @@ -471,7 +528,7 @@
3341  #else
3342        cn = buf;
3343  #endif
3344 -      h = ifconfig_pool_acquire (p, &local, &remote, cn);
3345 +      h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
3346        if (h < 0)
3347         break;
3348        msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
3349 @@ -506,7 +563,7 @@
3350  #else
3351        cn = buf;
3352  #endif
3353 -      h = ifconfig_pool_acquire (p, &local, &remote, cn);
3354 +      h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
3355        if (h < 0)
3356         break;
3357        msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
3358 diff -durN openvpn-2.2.2.orig/pool.h openvpn-2.2.2/pool.h
3359 --- openvpn-2.2.2.orig/pool.h   2011-12-13 17:58:56.000000000 +0100
3360 +++ openvpn-2.2.2/pool.h        2012-06-01 10:40:28.000000000 +0200
3361 @@ -52,6 +52,9 @@
3362    int size;
3363    int type;
3364    bool duplicate_cn;
3365 +  bool ipv6;
3366 +  struct in6_addr base_ipv6;
3367 +  unsigned int size_ipv6;
3368    struct ifconfig_pool_entry *list;
3369  };
3370  
3371 @@ -63,13 +66,13 @@
3372  
3373  typedef int ifconfig_pool_handle;
3374  
3375 -struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn);
3376 +struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits );
3377  
3378  void ifconfig_pool_free (struct ifconfig_pool *pool);
3379  
3380  bool ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end);
3381  
3382 -ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name);
3383 +ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name);
3384  
3385  bool ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard);
3386  
3387 diff -durN openvpn-2.2.2.orig/proto.h openvpn-2.2.2/proto.h
3388 --- openvpn-2.2.2.orig/proto.h  2011-12-13 17:58:56.000000000 +0100
3389 +++ openvpn-2.2.2/proto.h       2012-06-01 10:40:28.000000000 +0200
3390 @@ -108,6 +108,21 @@
3391  };
3392  
3393  /*
3394 + * IPv6 header
3395 + */
3396 +struct openvpn_ipv6hdr {
3397 +        uint8_t                version_prio;
3398 +        uint8_t                flow_lbl[3];
3399 +        uint16_t       payload_len;
3400 +        uint8_t                nexthdr;
3401 +        uint8_t                hop_limit;
3402 +
3403 +        struct  in6_addr        saddr;
3404 +        struct  in6_addr        daddr;
3405 +};
3406 +
3407 +
3408 +/*
3409   * UDP header
3410   */
3411  struct openvpn_udphdr {
3412 diff -durN openvpn-2.2.2.orig/push.c openvpn-2.2.2/push.c
3413 --- openvpn-2.2.2.orig/push.c   2011-12-13 17:58:56.000000000 +0100
3414 +++ openvpn-2.2.2/push.c        2012-06-01 10:40:28.000000000 +0200
3415 @@ -189,8 +189,26 @@
3416    const int safe_cap = BCAP (&buf) - extra;
3417    bool push_sent = false;
3418  
3419 +  msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap );
3420 +
3421    buf_printf (&buf, "%s", cmd);
3422  
3423 +  if ( c->c2.push_ifconfig_ipv6_defined )
3424 +    {
3425 +      /* IPv6 is put into buffer first, could be lengthy */
3426 +      /* TODO: push "/netbits" as well, to allow non-/64 subnet sizes
3427 +       *       (needs changes in options.c, options.h, and other places)
3428 +       */
3429 +      buf_printf( &buf, ",ifconfig-ipv6 %s %s",
3430 +                   print_in6_addr( c->c2.push_ifconfig_ipv6_local, 0, &gc),
3431 +                   print_in6_addr( c->c2.push_ifconfig_ipv6_remote, 0, &gc) );
3432 +      if (BLEN (&buf) >= safe_cap)
3433 +       {
3434 +         msg (M_WARN, "--push ifconfig-ipv6 option is too long");
3435 +         goto fail;
3436 +       }
3437 +    }
3438 +
3439    while (e)
3440      {
3441        if (e->enable)
3442 diff -durN openvpn-2.2.2.orig/route.c openvpn-2.2.2/route.c
3443 --- openvpn-2.2.2.orig/route.c  2011-12-13 17:58:56.000000000 +0100
3444 +++ openvpn-2.2.2/route.c       2012-06-01 10:40:28.000000000 +0200
3445 @@ -35,6 +35,7 @@
3446  #include "socket.h"
3447  #include "manage.h"
3448  #include "win32.h"
3449 +#include "options.h"
3450  
3451  #include "memdbg.h"
3452  
3453 @@ -68,6 +69,15 @@
3454    return ret;
3455  }
3456  
3457 +struct route_ipv6_option_list *
3458 +new_route_ipv6_option_list (const int max_routes, struct gc_arena *a)
3459 +{
3460 +  struct route_ipv6_option_list *ret;
3461 +  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_option_list, struct route_ipv6_option, max_routes, a);
3462 +  ret->capacity = max_routes;
3463 +  return ret;
3464 +}
3465 +
3466  struct route_option_list *
3467  clone_route_option_list (const struct route_option_list *src, struct gc_arena *a)
3468  {
3469 @@ -95,6 +105,15 @@
3470    return ret;
3471  }
3472  
3473 +struct route_ipv6_list *
3474 +new_route_ipv6_list (const int max_routes, struct gc_arena *a)
3475 +{
3476 +  struct route_ipv6_list *ret;
3477 +  ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_list, struct route_ipv6, max_routes, a);
3478 +  ret->capacity = max_routes;
3479 +  return ret;
3480 +}
3481 +
3482  static const char *
3483  route_string (const struct route *r, struct gc_arena *gc)
3484  {
3485 @@ -311,6 +330,68 @@
3486    return false;
3487  }
3488  
3489 +static bool
3490 +init_route_ipv6 (struct route_ipv6 *r6,
3491 +                const struct route_ipv6_option *r6o,
3492 +                const struct route_ipv6_list *rl6 )
3493 +{
3494 +  r6->option = r6o;
3495 +  r6->defined = false;
3496 +
3497 +  if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, NULL, M_WARN ))
3498 +    goto fail;
3499 +
3500 +  /* gateway */
3501 +  if (is_route_parm_defined (r6o->gateway))
3502 +    {
3503 +      if ( inet_pton( AF_INET6, r6o->gateway, &r6->gateway ) != 1 )
3504 +        {
3505 +         msg( M_WARN, PACKAGE_NAME "ROUTE6: cannot parse gateway spec '%s'", r6o->gateway );
3506 +        }
3507 +    }
3508 +  else if (rl6->remote_endpoint_defined)
3509 +    {
3510 +      r6->gateway = rl6->remote_endpoint_ipv6;
3511 +    }
3512 +  else
3513 +    {
3514 +      msg (M_WARN, PACKAGE_NAME " ROUTE6: " PACKAGE_NAME " needs a gateway parameter for a --route-ipv6 option and no default was specified by either --route-ipv6-gateway or --ifconfig-ipv6 options");
3515 +      goto fail;
3516 +    }
3517 +
3518 +  /* metric */
3519 +
3520 +  r6->metric_defined = false;
3521 +  r6->metric = 0;
3522 +  if (is_route_parm_defined (r6o->metric))
3523 +    {
3524 +      r6->metric = atoi (r6o->metric);
3525 +      if (r6->metric < 0)
3526 +       {
3527 +         msg (M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0",
3528 +              r6o->prefix,
3529 +              r6o->metric);
3530 +         goto fail;
3531 +       }
3532 +      r6->metric_defined = true;
3533 +    }
3534 +  else if (rl6->default_metric_defined)
3535 +    {
3536 +      r6->metric = rl6->default_metric;
3537 +      r6->metric_defined = true;
3538 +    }
3539 +
3540 +  r6->defined = true;
3541 +
3542 +  return true;
3543 +
3544 + fail:
3545 +  msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s",
3546 +       r6o->prefix);
3547 +  r6->defined = false;
3548 +  return false;
3549 +}
3550 +
3551  void
3552  add_route_to_option_list (struct route_option_list *l,
3553                           const char *network,
3554 @@ -331,6 +412,23 @@
3555  }
3556  
3557  void
3558 +add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
3559 +                         const char *prefix,
3560 +                         const char *gateway,
3561 +                         const char *metric)
3562 +{
3563 +  struct route_ipv6_option *ro;
3564 +  if (l->n >= l->capacity)
3565 +    msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d IPv6 routes -- please increase the max-routes option in the client configuration file",
3566 +        l->capacity);
3567 +  ro = &l->routes_ipv6[l->n];
3568 +  ro->prefix = prefix;
3569 +  ro->gateway = gateway;
3570 +  ro->metric = metric;
3571 +  ++l->n;
3572 +}
3573 +
3574 +void
3575  clear_route_list (struct route_list *rl)
3576  {
3577    const int capacity = rl->capacity;
3578 @@ -340,6 +438,15 @@
3579  }
3580  
3581  void
3582 +clear_route_ipv6_list (struct route_ipv6_list *rl6)
3583 +{
3584 +  const int capacity = rl6->capacity;
3585 +  const size_t rl6_size = array_mult_safe (sizeof(struct route_ipv6), capacity, sizeof(struct route_ipv6_list));
3586 +  memset(rl6, 0, rl6_size);
3587 +  rl6->capacity = capacity;
3588 +}
3589 +
3590 +void
3591  route_list_add_default_gateway (struct route_list *rl,
3592                                 struct env_set *es,
3593                                 const in_addr_t addr)
3594 @@ -469,6 +576,72 @@
3595    return ret;
3596  }
3597  
3598 +bool
3599 +init_route_ipv6_list (struct route_ipv6_list *rl6,
3600 +                const struct route_ipv6_option_list *opt6,
3601 +                const char *remote_endpoint,
3602 +                int default_metric,
3603 +                struct env_set *es)
3604 +{
3605 +  struct gc_arena gc = gc_new ();
3606 +  bool ret = true;
3607 +
3608 +  clear_route_ipv6_list (rl6);
3609 +
3610 +  rl6->flags = opt6->flags;
3611 +
3612 +  if (default_metric)
3613 +    {
3614 +      rl6->default_metric = default_metric;
3615 +      rl6->default_metric_defined = true;
3616 +    }
3617 +
3618 +  /* "default_gateway" is stuff for "redirect-gateway", which we don't
3619 +   * do for IPv6 yet -> TODO
3620 +   */
3621 +    {
3622 +      dmsg (D_ROUTE, "ROUTE6: default_gateway=UNDEF");
3623 +    }
3624 +
3625 +  if ( is_route_parm_defined( remote_endpoint ))
3626 +    {
3627 +      if ( inet_pton( AF_INET6, remote_endpoint, 
3628 +                       &rl6->remote_endpoint_ipv6) == 1 )
3629 +        {
3630 +         rl6->remote_endpoint_defined = true;
3631 +        }
3632 +      else
3633 +       {
3634 +         msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", remote_endpoint);
3635 +          ret = false;
3636 +       }
3637 +    }
3638 +  else
3639 +    rl6->remote_endpoint_defined = false;
3640 +
3641 +
3642 +  if (!(opt6->n >= 0 && opt6->n <= rl6->capacity))
3643 +    msg (M_FATAL, PACKAGE_NAME " ROUTE6: (init) number of route options (%d) is greater than route list capacity (%d)", opt6->n, rl6->capacity);
3644 +
3645 +  /* parse the routes from opt to rl6 */
3646 +  {
3647 +    int i, j = 0;
3648 +    for (i = 0; i < opt6->n; ++i)
3649 +      {
3650 +       if (!init_route_ipv6 (&rl6->routes_ipv6[j],
3651 +                             &opt6->routes_ipv6[i],
3652 +                             rl6 ))
3653 +         ret = false;
3654 +       else
3655 +         ++j;
3656 +      }
3657 +    rl6->n = j;
3658 +  }
3659 +
3660 +  gc_free (&gc);
3661 +  return ret;
3662 +}
3663 +
3664  static void
3665  add_route3 (in_addr_t network,
3666             in_addr_t netmask,
3667 @@ -704,10 +877,13 @@
3668  }
3669  
3670  void
3671 -add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3672 +add_routes (struct route_list *rl, struct route_ipv6_list *rl6,
3673 +           const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3674  {
3675 -  redirect_default_route_to_vpn (rl, tt, flags, es);
3676 -  if (!rl->routes_added)
3677 +  if (rl) 
3678 +      redirect_default_route_to_vpn (rl, tt, flags, es);
3679 +
3680 +  if (rl && !rl->routes_added)
3681      {
3682        int i;
3683  
3684 @@ -732,12 +908,27 @@
3685         }
3686        rl->routes_added = true;
3687      }
3688 +
3689 +  if (rl6 && !rl6->routes_added)
3690 +    {
3691 +      int i;
3692 +
3693 +      for (i = 0; i < rl6->n; ++i)
3694 +       {
3695 +         struct route_ipv6 *r = &rl6->routes_ipv6[i];
3696 +         if (flags & ROUTE_DELETE_FIRST)
3697 +           delete_route_ipv6 (r, tt, flags, es);
3698 +         add_route_ipv6 (r, tt, flags, es);
3699 +       }
3700 +      rl6->routes_added = true;
3701 +    }
3702  }
3703  
3704  void
3705 -delete_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3706 +delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
3707 +              const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3708  {
3709 -  if (rl->routes_added)
3710 +  if (rl && rl->routes_added)
3711      {
3712        int i;
3713        for (i = rl->n - 1; i >= 0; --i)
3714 @@ -747,9 +938,28 @@
3715         }
3716        rl->routes_added = false;
3717      }
3718 -  undo_redirect_default_route_to_vpn (rl, tt, flags, es);
3719  
3720 -  clear_route_list (rl);
3721 +  if ( rl )
3722 +    {
3723 +      undo_redirect_default_route_to_vpn (rl, tt, flags, es);
3724 +      clear_route_list (rl);
3725 +    }
3726 +
3727 +  if ( rl6 && rl6->routes_added )
3728 +    {
3729 +      int i;
3730 +      for (i = rl6->n - 1; i >= 0; --i)
3731 +       {
3732 +         const struct route_ipv6 *r6 = &rl6->routes_ipv6[i];
3733 +         delete_route_ipv6 (r6, tt, flags, es);
3734 +       }
3735 +      rl6->routes_added = false;
3736 +    }
3737 +
3738 +  if ( rl6 )
3739 +    {
3740 +      clear_route_ipv6_list (rl6);
3741 +    }
3742  }
3743  
3744  #ifdef ENABLE_DEBUG
3745 @@ -832,6 +1042,34 @@
3746      setenv_route (es, &rl->routes[i], i + 1);
3747  }
3748  
3749 +static void
3750 +setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
3751 +{
3752 +  struct gc_arena gc = gc_new ();
3753 +  if (r6->defined)
3754 +    {
3755 +      struct buffer name1 = alloc_buf_gc( 256, &gc );
3756 +      struct buffer val = alloc_buf_gc( 256, &gc );
3757 +      struct buffer name2 = alloc_buf_gc( 256, &gc );
3758 +
3759 +      buf_printf( &name1, "route_ipv6_network_%d", i );
3760 +      buf_printf( &val, "%s/%d", print_in6_addr( r6->network, 0, &gc ),
3761 +                                r6->netbits );
3762 +      setenv_str( es, BSTR(&name1), BSTR(&val) );
3763 +
3764 +      buf_printf( &name2, "route_ipv6_gateway_%d", i );
3765 +      setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc ));
3766 +    }
3767 +  gc_free (&gc);
3768 +}
3769 +void
3770 +setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6)
3771 +{
3772 +  int i;
3773 +  for (i = 0; i < rl6->n; ++i)
3774 +    setenv_route_ipv6 (es, &rl6->routes_ipv6[i], i + 1);
3775 +}
3776 +
3777  void
3778  add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3779  {
3780 @@ -1025,6 +1263,187 @@
3781    gc_free (&gc);
3782  }
3783  
3784 +
3785 +static const char * 
3786 +print_in6_addr_netbits_only( struct in6_addr network_copy, int netbits, 
3787 +                             struct gc_arena * gc)
3788 +{
3789 +  /* clear host bit parts of route 
3790 +   * (needed if routes are specified improperly, or if we need to 
3791 +   * explicitely setup/clear the "connected" network routes on some OSes)
3792 +   */
3793 +  int byte = 15;
3794 +  int bits_to_clear = 128 - netbits;
3795 +
3796 +  while( byte >= 0 && bits_to_clear > 0 )
3797 +    {
3798 +      if ( bits_to_clear >= 8 )
3799 +       { network_copy.s6_addr[byte--] = 0; bits_to_clear -= 8; }
3800 +      else
3801 +       { network_copy.s6_addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
3802 +    }
3803 +
3804 +  return print_in6_addr( network_copy, 0, gc);
3805 +}
3806 +
3807 +void
3808 +add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3809 +{
3810 +  struct gc_arena gc;
3811 +  struct argv argv;
3812 +
3813 +  const char *network;
3814 +  const char *gateway;
3815 +  bool status = false;
3816 +  const char *device = tt->actual_name;
3817 +
3818 +  if (!r6->defined)
3819 +    return;
3820 +
3821 +  gc_init (&gc);
3822 +  argv_init (&argv);
3823 +
3824 +  network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc);
3825 +  gateway = print_in6_addr( r6->gateway, 0, &gc);
3826 +
3827 +  if ( !tt->ipv6 )
3828 +    {
3829 +      msg( M_INFO, "add_route_ipv6(): not adding %s/%d, no IPv6 on if %s",
3830 +                   network, r6->netbits, device );
3831 +      return;
3832 +    }
3833 +
3834 +  msg( M_INFO, "add_route_ipv6(%s/%d -> %s metric %d) dev %s",
3835 +               network, r6->netbits, gateway, r6->metric, device );
3836 +
3837 +  /*
3838 +   * Filter out routes which are essentially no-ops
3839 +   * (not currently done for IPv6)
3840 +   */
3841 +
3842 +#if defined(TARGET_LINUX)
3843 +#ifdef CONFIG_FEATURE_IPROUTE
3844 +  argv_printf (&argv, "%s -6 route add %s/%d dev %s",
3845 +             iproute_path,
3846 +             network,
3847 +             r6->netbits,
3848 +             device);
3849 +  if (r6->metric_defined)
3850 +    argv_printf_cat (&argv, " metric %d", r6->metric);
3851 +
3852 +#else
3853 +  argv_printf (&argv, "%s -A inet6 add %s/%d dev %s",
3854 +               ROUTE_PATH,
3855 +             network,
3856 +             r6->netbits,
3857 +             device);
3858 +  if (r6->metric_defined)
3859 +    argv_printf_cat (&argv, " metric %d", r6->metric);
3860 +#endif  /*CONFIG_FEATURE_IPROUTE*/
3861 +  argv_msg (D_ROUTE, &argv);
3862 +  status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed");
3863 +
3864 +#elif defined (WIN32)
3865 +
3866 +  /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
3867 +  argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s",
3868 +              get_win_sys_path(),
3869 +              NETSH_PATH_SUFFIX,
3870 +              network,
3871 +              r6->netbits,
3872 +              device);
3873 +
3874 +  /* next-hop depends on TUN or TAP mode:
3875 +   * - in TAP mode, we use the "real" next-hop
3876 +   * - in TUN mode we use a special-case link-local address that the tapdrvr
3877 +   *   knows about and will answer ND (neighbor discovery) packets for
3878 +   */
3879 +  if ( tt->type == DEV_TYPE_TUN )
3880 +       argv_printf_cat( &argv, " %s", "fe80::8" );
3881 +  else
3882 +       argv_printf_cat( &argv, " %s", gateway );
3883 +
3884 +#if 0
3885 +  if (r->metric_defined)
3886 +    argv_printf_cat (&argv, " METRIC %d", r->metric);
3887 +#endif
3888 +
3889 +  /* in some versions of Windows, routes are persistent across reboots by
3890 +   * default, unless "store=active" is set (pointed out by Tony Lim, thanks)
3891 +   */
3892 +  argv_printf_cat( &argv, " store=active" );
3893 +
3894 +  argv_msg (D_ROUTE, &argv);
3895 +
3896 +  netcmd_semaphore_lock ();
3897 +  status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed");
3898 +  netcmd_semaphore_release ();
3899 +
3900 +#elif defined (TARGET_SOLARIS)
3901 +
3902 +  /* example: route add -inet6 2001:db8::/32 somegateway 0 */
3903 +
3904 +  /* for some weird reason, this does not work for me unless I set
3905 +   * "metric 0" - otherwise, the routes will be nicely installed, but
3906 +   * packets will just disappear somewhere.  So we use "0" now...
3907 +   */
3908 +
3909 +  argv_printf (&argv, "%s add -inet6 %s/%d %s 0",
3910 +               ROUTE_PATH,
3911 +               network,
3912 +               r6->netbits,
3913 +               gateway );
3914 +
3915 +  argv_msg (D_ROUTE, &argv);
3916 +  status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add -inet6 command failed");
3917 +
3918 +#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
3919 +
3920 +  argv_printf (&argv, "%s add -inet6 %s/%d -iface %s",
3921 +               ROUTE_PATH,
3922 +               network,
3923 +               r6->netbits,
3924 +               device );
3925 +
3926 +  argv_msg (D_ROUTE, &argv);
3927 +  status = openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route add -inet6 command failed");
3928 +
3929 +#elif defined(TARGET_DARWIN) 
3930 +
3931 +  argv_printf (&argv, "%s add -inet6 %s -prefixlen %d -iface %s",
3932 +               ROUTE_PATH,
3933 +               network, r6->netbits, device );
3934 +
3935 +  argv_msg (D_ROUTE, &argv);
3936 +  status = openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route add -inet6 command failed");
3937 +
3938 +#elif defined(TARGET_OPENBSD)
3939 +
3940 +  argv_printf (&argv, "%s add -inet6 %s -prefixlen %d %s",
3941 +               ROUTE_PATH,
3942 +               network, r6->netbits, gateway );
3943 +
3944 +  argv_msg (D_ROUTE, &argv);
3945 +  status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route add -inet6 command failed");
3946 +
3947 +#elif defined(TARGET_NETBSD)
3948 +
3949 +  argv_printf (&argv, "%s add -inet6 %s/%d %s",
3950 +               ROUTE_PATH,
3951 +               network, r6->netbits, gateway );
3952 +
3953 +  argv_msg (D_ROUTE, &argv);
3954 +  status = openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route add -inet6 command failed");
3955 +
3956 +#else
3957 +  msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system.  Try putting your routes in a --route-up script");
3958 +#endif
3959 +
3960 +  r6->defined = status;
3961 +  argv_reset (&argv);
3962 +  gc_free (&gc);
3963 +}
3964 +
3965  static void
3966  delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3967  {
3968 @@ -1161,6 +1580,142 @@
3969  #endif
3970  
3971    argv_reset (&argv);
3972 +  gc_free (&gc);
3973 +}
3974 +
3975 +void
3976 +delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
3977 +{
3978 +  struct gc_arena gc;
3979 +  struct argv argv;
3980 +  const char *network;
3981 +  const char *gateway;
3982 +  const char *device = tt->actual_name;
3983 +
3984 +  if (!r6->defined)
3985 +    return;
3986 +
3987 +  gc_init (&gc);
3988 +  argv_init (&argv);
3989 +
3990 +  network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc);
3991 +  gateway = print_in6_addr( r6->gateway, 0, &gc);
3992 +
3993 +  if ( !tt->ipv6 )
3994 +    {
3995 +      msg( M_INFO, "delete_route_ipv6(): not deleting %s/%d, no IPv6 on if %s",
3996 +                   network, r6->netbits, device );
3997 +      return;
3998 +    }
3999 +
4000 +  msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits );
4001 +
4002 +#if defined(TARGET_LINUX)
4003 +#ifdef CONFIG_FEATURE_IPROUTE
4004 +  argv_printf (&argv, "%s -6 route del %s/%d dev %s",
4005 +             iproute_path,
4006 +             network,
4007 +             r6->netbits,
4008 +             device);
4009 +#else
4010 +  argv_printf (&argv, "%s -A inet6 del %s/%d dev %s",
4011 +               ROUTE_PATH,
4012 +             network,
4013 +             r6->netbits,
4014 +             device);
4015 +#endif  /*CONFIG_FEATURE_IPROUTE*/
4016 +  argv_msg (D_ROUTE, &argv);
4017 +  openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed");
4018 +
4019 +#elif defined (WIN32)
4020 +
4021 +  /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
4022 +  argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s",
4023 +              get_win_sys_path(),
4024 +              NETSH_PATH_SUFFIX,
4025 +              network,
4026 +              r6->netbits,
4027 +              device);
4028 +
4029 +  /* next-hop depends on TUN or TAP mode:
4030 +   * - in TAP mode, we use the "real" next-hop
4031 +   * - in TUN mode we use a special-case link-local address that the tapdrvr
4032 +   *   knows about and will answer ND (neighbor discovery) packets for
4033 +   * (and "route deletion without specifying next-hop" does not work...)
4034 +   */
4035 +  if ( tt->type == DEV_TYPE_TUN )
4036 +       argv_printf_cat( &argv, " %s", "fe80::8" );
4037 +  else
4038 +       argv_printf_cat( &argv, " %s", gateway );
4039 +
4040 +#if 0
4041 +  if (r->metric_defined)
4042 +    argv_printf_cat (&argv, "METRIC %d", r->metric);
4043 +#endif
4044 +
4045 +  argv_msg (D_ROUTE, &argv);
4046 +
4047 +  netcmd_semaphore_lock ();
4048 +  openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed");
4049 +  netcmd_semaphore_release ();
4050 +
4051 +#elif defined (TARGET_SOLARIS)
4052 +
4053 +  /* example: route delete -inet6 2001:db8::/32 somegateway */
4054 +  /* GERT-TODO: this is untested, but should work */
4055 +
4056 +  argv_printf (&argv, "%s delete -inet6 %s/%d %s",
4057 +               ROUTE_PATH,
4058 +               network,
4059 +               r6->netbits,
4060 +               gateway );
4061 +
4062 +  argv_msg (D_ROUTE, &argv);
4063 +  openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed");
4064 +
4065 +#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
4066 +
4067 +  argv_printf (&argv, "%s delete -inet6 %s/%d -iface %s",
4068 +               ROUTE_PATH,
4069 +               network,
4070 +               r6->netbits,
4071 +               device );
4072 +
4073 +  argv_msg (D_ROUTE, &argv);
4074 +  openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed");
4075 +
4076 +#elif defined(TARGET_DARWIN) 
4077 +
4078 +  argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d -iface %s",
4079 +               ROUTE_PATH, 
4080 +               network, r6->netbits, device );
4081 +
4082 +  argv_msg (D_ROUTE, &argv);
4083 +  openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed");
4084 +
4085 +#elif defined(TARGET_OPENBSD)
4086 +
4087 +  argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d %s",
4088 +               ROUTE_PATH,
4089 +               network, r6->netbits, gateway );
4090 +
4091 +  argv_msg (D_ROUTE, &argv);
4092 +  openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route delete -inet6 command failed");
4093 +
4094 +#elif defined(TARGET_NETBSD)
4095 +
4096 +  argv_printf (&argv, "%s delete -inet6 %s/%d %s",
4097 +               ROUTE_PATH,
4098 +               network, r6->netbits, gateway );
4099 +
4100 +  argv_msg (D_ROUTE, &argv);
4101 +  openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed");
4102 +
4103 +#else
4104 +  msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system.  Try putting your routes in a --route-down script");
4105 +#endif
4106 +
4107 +  argv_reset (&argv);
4108    gc_free (&gc);
4109  }
4110  
4111 diff -durN openvpn-2.2.2.orig/route.h openvpn-2.2.2/route.h
4112 --- openvpn-2.2.2.orig/route.h  2011-12-13 17:58:56.000000000 +0100
4113 +++ openvpn-2.2.2/route.h       2012-06-01 10:40:28.000000000 +0200
4114 @@ -92,6 +92,19 @@
4115    struct route_option routes[EMPTY_ARRAY_SIZE];
4116  };
4117  
4118 +struct route_ipv6_option {
4119 +  const char *prefix;          /* e.g. "2001:db8:1::/64" */
4120 +  const char *gateway;         /* e.g. "2001:db8:0::2" */
4121 +  const char *metric;          /* e.g. "5" */
4122 +};
4123 +
4124 +struct route_ipv6_option_list {
4125 +  unsigned int flags;
4126 +  int capacity;
4127 +  int n;
4128 +  struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE];
4129 +};
4130 +
4131  struct route {
4132    bool defined;
4133    const struct route_option *option;
4134 @@ -113,6 +126,31 @@
4135    struct route routes[EMPTY_ARRAY_SIZE];
4136  };
4137  
4138 +struct route_ipv6 {
4139 +  bool defined;
4140 +  const struct route_ipv6_option *option;
4141 +  struct in6_addr network;
4142 +  unsigned int netbits;
4143 +  struct in6_addr gateway;
4144 +  bool metric_defined;
4145 +  int metric;
4146 +};
4147 +
4148 +struct route_ipv6_list {
4149 +  bool routes_added;
4150 +  unsigned int flags;
4151 +  int default_metric;
4152 +  bool default_metric_defined;
4153 +  struct in6_addr remote_endpoint_ipv6;
4154 +  bool remote_endpoint_defined;
4155 +  bool did_redirect_default_gateway;                   /* TODO (?) */
4156 +  bool did_local;                                      /* TODO (?) */
4157 +  int capacity;
4158 +  int n;
4159 +  struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE];
4160 +};
4161 +
4162 +
4163  #if P2MP
4164  /* internal OpenVPN route */
4165  struct iroute {
4166 @@ -120,15 +158,25 @@
4167    int netbits;
4168    struct iroute *next;
4169  };
4170 +
4171 +struct iroute_ipv6 {
4172 +  struct in6_addr network;
4173 +  unsigned int netbits;
4174 +  struct iroute_ipv6 *next;
4175 +};
4176  #endif
4177  
4178  struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a);
4179 +struct route_ipv6_option_list *new_route_ipv6_option_list (const int max_routes, struct gc_arena *a);
4180  struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a);
4181  void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src);
4182  
4183  struct route_list *new_route_list (const int max_routes, struct gc_arena *a);
4184 +struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a);
4185  
4186  void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
4187 +void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
4188 +void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
4189  
4190  void add_route_to_option_list (struct route_option_list *l,
4191                                const char *network,
4192 @@ -136,6 +184,11 @@
4193                                const char *gateway,
4194                                const char *metric);
4195  
4196 +void add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
4197 +                              const char *prefix,
4198 +                              const char *gateway,
4199 +                              const char *metric);
4200 +
4201  bool init_route_list (struct route_list *rl,
4202                       const struct route_option_list *opt,
4203                       const char *remote_endpoint,
4204 @@ -143,21 +196,30 @@
4205                       in_addr_t remote_host,
4206                       struct env_set *es);
4207  
4208 +bool init_route_ipv6_list (struct route_ipv6_list *rl6,
4209 +                     const struct route_ipv6_option_list *opt6,
4210 +                     const char *remote_endpoint,
4211 +                     int default_metric,
4212 +                     struct env_set *es);
4213 +
4214  void route_list_add_default_gateway (struct route_list *rl,
4215                                      struct env_set *es,
4216                                      const in_addr_t addr);
4217  
4218  void add_routes (struct route_list *rl,
4219 +                struct route_ipv6_list *rl6,
4220                  const struct tuntap *tt,
4221                  unsigned int flags,
4222                  const struct env_set *es);
4223  
4224  void delete_routes (struct route_list *rl,
4225 +                   struct route_ipv6_list *rl6,
4226                     const struct tuntap *tt,
4227                     unsigned int flags,
4228                     const struct env_set *es);
4229  
4230  void setenv_routes (struct env_set *es, const struct route_list *rl);
4231 +void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6);
4232  
4233  bool is_special_addr (const char *addr_str);
4234  
4235 diff -durN openvpn-2.2.2.orig/socket.c openvpn-2.2.2/socket.c
4236 --- openvpn-2.2.2.orig/socket.c 2011-12-13 17:58:56.000000000 +0100
4237 +++ openvpn-2.2.2/socket.c      2012-06-01 10:40:28.000000000 +0200
4238 @@ -342,6 +342,24 @@
4239    }
4240  }
4241  
4242 +bool
4243 +ipv6_addr_safe (const char *ipv6_text_addr)
4244 +{
4245 +  /* verify non-NULL */
4246 +  if (!ipv6_text_addr)
4247 +    return false;
4248 +
4249 +  /* verify length is within limits */
4250 +  if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN )
4251 +    return false;
4252 +
4253 +  /* verify that string will convert to IPv6 address */
4254 +  {
4255 +    struct in6_addr a6;
4256 +    return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
4257 +  }
4258 +}
4259 +
4260  static bool
4261  dns_addr_safe (const char *addr)
4262  {
4263 @@ -2032,6 +2050,55 @@
4264    return BSTR (&out);
4265  }
4266  
4267 +/*
4268 + * Convert an in6_addr in host byte order
4269 + * to an ascii representation of an IPv6 address
4270 + */
4271 +const char *
4272 +print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
4273 +{
4274 +  struct buffer out = alloc_buf_gc (64, gc);
4275 +  char tmp_out_buf[64];                /* inet_ntop wants pointer to buffer */
4276 +
4277 +  if ( memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 || 
4278 +       !(flags & IA_EMPTY_IF_UNDEF))
4279 +    {
4280 +      inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1);
4281 +      buf_printf (&out, "%s", tmp_out_buf );
4282 +    }
4283 +  return BSTR (&out);
4284 +}
4285 +
4286 +/* add some offset to an ipv6 address
4287 + * (add in steps of 32 bits, taking overflow into next round)
4288 + */
4289 +#ifndef s6_addr32
4290 +# ifdef TARGET_SOLARIS
4291 +#  define s6_addr32 _S6_un._S6_u32
4292 +# else
4293 +#  define s6_addr32 __u6_addr.__u6_addr32
4294 +# endif
4295 +#endif
4296 +#ifndef UINT32_MAX
4297 +# define UINT32_MAX (4294967295U)
4298 +#endif
4299 +struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add )
4300 +{
4301 +    int i;
4302 +    uint32_t h;
4303 +
4304 +    for( i=3; i>=0 && add > 0 ; i-- )
4305 +    {
4306 +       h = ntohl( base.s6_addr32[i] );
4307 +       base.s6_addr32[i] = htonl( (h+add) & UINT32_MAX );
4308 +       /* 32-bit overrun? 
4309 +        * caveat: can't do "h+add > UINT32_MAX" with 32bit math!
4310 +         */
4311 +       add = ( h > UINT32_MAX - add )?  1: 0;
4312 +    }
4313 +    return base;
4314 +}
4315 +
4316  /* set environmental variables for ip/port in *addr */
4317  void
4318  setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags)
4319 @@ -2337,6 +2404,58 @@
4320  
4321  #ifdef WIN32
4322  
4323 +/*
4324 + * inet_ntop() and inet_pton() wrap-implementations using
4325 + * WSAAddressToString() and WSAStringToAddress() functions
4326 + */
4327 +const char *
4328 +inet_ntop(int af, const void *src, char *dst, socklen_t size)
4329 +{
4330 +  struct sockaddr_storage ss;
4331 +  unsigned long s = size;
4332 +
4333 +  CLEAR(ss);
4334 +  ss.ss_family = af;
4335 +
4336 +  switch(af) {
4337 +    case AF_INET:
4338 +      ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
4339 +      break;
4340 +    case AF_INET6:
4341 +      ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
4342 +      break;
4343 +    default:
4344 +      ASSERT (0);
4345 +  }
4346 +  // cannot direclty use &size because of strict aliasing rules
4347 +  return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)?
4348 +          dst : NULL;
4349 +}
4350 +
4351 +int
4352 +inet_pton(int af, const char *src, void *dst)
4353 +{
4354 +  struct sockaddr_storage ss;
4355 +  int size = sizeof(ss);
4356 +  char src_copy[INET6_ADDRSTRLEN+1];
4357 +
4358 +  CLEAR(ss);
4359 +  // stupid non-const API
4360 +  strncpynt(src_copy, src, INET6_ADDRSTRLEN+1);
4361 +
4362 +  if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) {
4363 +    switch(af) {
4364 +      case AF_INET:
4365 +       *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
4366 +       return 1;
4367 +      case AF_INET6:
4368 +       *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
4369 +       return 1;
4370 +    }
4371 +  }
4372 +  return 0;
4373 +}
4374 +
4375  int
4376  socket_recv_queue (struct link_socket *sock, int maxsize)
4377  {
4378 diff -durN openvpn-2.2.2.orig/socket.h openvpn-2.2.2/socket.h
4379 --- openvpn-2.2.2.orig/socket.h 2011-12-13 17:58:56.000000000 +0100
4380 +++ openvpn-2.2.2/socket.h      2012-06-01 10:40:28.000000000 +0200
4381 @@ -351,6 +351,8 @@
4382  #define IA_EMPTY_IF_UNDEF (1<<0)
4383  #define IA_NET_ORDER      (1<<1)
4384  const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc);
4385 +const char *print_in6_addr  (struct in6_addr addr6, unsigned int flags, struct gc_arena *gc);
4386 +struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add );
4387  
4388  #define SA_IP_PORT        (1<<0)
4389  #define SA_SET_IF_NONZERO (1<<1)
4390 @@ -404,6 +406,7 @@
4391  bool ip_addr_dotted_quad_safe (const char *dotted_quad);
4392  bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn);
4393  bool mac_addr_safe (const char *mac_addr);
4394 +bool ipv6_addr_safe (const char *ipv6_text_addr);
4395  
4396  socket_descriptor_t create_socket_tcp (void);
4397  
4398 diff -durN openvpn-2.2.2.orig/syshead.h openvpn-2.2.2/syshead.h
4399 --- openvpn-2.2.2.orig/syshead.h        2011-12-13 17:58:56.000000000 +0100
4400 +++ openvpn-2.2.2/syshead.h     2012-06-01 10:40:28.000000000 +0200
4401 @@ -28,6 +28,10 @@
4402  /*
4403   * Only include if not during configure
4404   */
4405 +#ifdef WIN32
4406 +/* USE_PF_INET6: win32 ipv6 exists only after 0x0501 (XP) */
4407 +#define WINVER 0x0501
4408 +#endif
4409  #ifndef PACKAGE_NAME
4410  #include "config.h"
4411  #endif
4412 @@ -339,6 +343,9 @@
4413  #ifdef WIN32
4414  #include <iphlpapi.h>
4415  #include <wininet.h>
4416 +/* The following two headers are needed of USE_PF_INET6 */
4417 +#include <winsock2.h>
4418 +#include <ws2tcpip.h>
4419  #endif
4420  
4421  #ifdef HAVE_SYS_MMAN_H
4422 diff -durN openvpn-2.2.2.orig/tun.c openvpn-2.2.2/tun.c
4423 --- openvpn-2.2.2.orig/tun.c    2011-12-13 17:58:56.000000000 +0100
4424 +++ openvpn-2.2.2/tun.c 2012-06-01 10:46:55.000000000 +0200
4425 @@ -56,13 +56,14 @@
4426                             const in_addr_t ip,
4427                             const in_addr_t netmask,
4428                             const unsigned int flags);
4429 +static void netsh_command (const struct argv *a, int n);
4430  
4431  static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);
4432  
4433  #endif
4434  
4435  #ifdef TARGET_SOLARIS
4436 -static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual);
4437 +static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6);
4438  #include <stropts.h>
4439  #endif
4440  
4441 @@ -129,30 +130,6 @@
4442    return dev;
4443  }
4444  
4445 -/*
4446 - * Called by the open_tun function of OSes to check if we
4447 - * explicitly support IPv6.
4448 - *
4449 - * In this context, explicit means that the OS expects us to
4450 - * do something special to the tun socket in order to support
4451 - * IPv6, i.e. it is not transparent.
4452 - *
4453 - * ipv6_explicitly_supported should be set to false if we don't
4454 - * have any explicit IPv6 code in the tun device handler.
4455 - *
4456 - * If ipv6_explicitly_supported is true, then we have explicit
4457 - * OS-specific tun dev code for handling IPv6.  If so, tt->ipv6
4458 - * is set according to the --tun-ipv6 command line option.
4459 - */
4460 -static void
4461 -ipv6_support (bool ipv6, bool ipv6_explicitly_supported, struct tuntap* tt)
4462 -{
4463 -  tt->ipv6 = false;
4464 -  if (ipv6_explicitly_supported)
4465 -    tt->ipv6 = ipv6;
4466 -  else if (ipv6)
4467 -    msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
4468 -}
4469  
4470  /* --ifconfig-nowarn disables some options sanity checking */
4471  static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)";
4472 @@ -423,6 +400,8 @@
4473           int topology,          /* one of the TOP_x values */
4474           const char *ifconfig_local_parm,          /* --ifconfig parm 1 */
4475           const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
4476 +         const char *ifconfig_ipv6_local_parm,     /* --ifconfig parm 1 IPv6 */
4477 +         const char *ifconfig_ipv6_remote_parm,    /* --ifconfig parm 2 IPv6 */
4478           in_addr_t local_public,
4479           in_addr_t remote_public,
4480           const bool strict_warn,
4481 @@ -537,6 +516,40 @@
4482  
4483        tt->did_ifconfig_setup = true;
4484      }
4485 +
4486 +  if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm)
4487 +    {
4488 +      const char *ifconfig_ipv6_local = NULL;
4489 +      const char *ifconfig_ipv6_remote = NULL;
4490 +
4491 +      /*
4492 +       * Convert arguments to binary IPv6 addresses.
4493 +       */
4494 +
4495 +      if ( inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 ||
4496 +           inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1 ) 
4497 +       {
4498 +         msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm );
4499 +       }
4500 +      tt->netbits_ipv6 = 64;
4501 +
4502 +      /*
4503 +       * Set ifconfig parameters
4504 +       */
4505 +      ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
4506 +      ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
4507 +
4508 +      /*
4509 +       * Set environmental variables with ifconfig parameters.
4510 +       */
4511 +      if (es)
4512 +       {
4513 +         setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local);
4514 +         setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote);
4515 +       }
4516 +      tt->did_ifconfig_ipv6_setup = true;
4517 +    }
4518 +
4519    gc_free (&gc);
4520    return tt;
4521  }
4522 @@ -559,6 +572,40 @@
4523  #endif
4524  }
4525  
4526 +#if defined(TARGET_WIN32) || \
4527 +    defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD)
4528 +
4529 +/* some of the platforms will auto-add a "network route" pointing
4530 + * to the interface on "ifconfig tunX 2001:db8::1/64", others need
4531 + * an extra call to "route add..."
4532 + * -> helper function to simplify code below
4533 + */
4534 +void add_route_connected_v6_net(struct tuntap * tt,
4535 +                               const struct env_set *es)
4536 +{
4537 +    struct route_ipv6 r6;
4538 +
4539 +    r6.defined = true;
4540 +    r6.network = tt->local_ipv6;
4541 +    r6.netbits = tt->netbits_ipv6;
4542 +    r6.gateway = tt->local_ipv6;
4543 +    add_route_ipv6 (&r6, tt, 0, es);
4544 +}
4545 +
4546 +void delete_route_connected_v6_net(struct tuntap * tt,
4547 +                                  const struct env_set *es)
4548 +{
4549 +    struct route_ipv6 r6;
4550 +
4551 +    r6.defined = true;
4552 +    r6.network = tt->local_ipv6;
4553 +    r6.netbits = tt->netbits_ipv6;
4554 +    r6.gateway = tt->local_ipv6;
4555 +    delete_route_ipv6 (&r6, tt, 0, es);
4556 +}
4557 +#endif
4558 +
4559 +
4560  /* execute the ifconfig command through the shell */
4561  void
4562  do_ifconfig (struct tuntap *tt,
4563 @@ -574,10 +621,16 @@
4564        const char *ifconfig_local = NULL;
4565        const char *ifconfig_remote_netmask = NULL;
4566        const char *ifconfig_broadcast = NULL;
4567 +      const char *ifconfig_ipv6_local = NULL;
4568 +      const char *ifconfig_ipv6_remote = NULL;
4569 +      bool do_ipv6 = false;
4570        struct argv argv;
4571  
4572        argv_init (&argv);
4573  
4574 +      msg( M_INFO, "do_ifconfig, tt->ipv6=%d, tt->did_ifconfig_ipv6_setup=%d",
4575 +                  tt->ipv6, tt->did_ifconfig_ipv6_setup );
4576 +
4577        /*
4578         * We only handle TUN/TAP devices here, not --dev null devices.
4579         */
4580 @@ -589,6 +642,13 @@
4581        ifconfig_local = print_in_addr_t (tt->local, 0, &gc);
4582        ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);
4583  
4584 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
4585 +        {
4586 +         ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
4587 +         ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
4588 +         do_ipv6 = true;
4589 +       }
4590 +
4591        /*
4592         * If TAP-style device, generate broadcast address.
4593         */
4594 @@ -647,7 +707,19 @@
4595                   argv_msg (M_INFO, &argv);
4596                   openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed");
4597         }
4598 -       tt->did_ifconfig = true;
4599 +      if ( do_ipv6 )
4600 +       {
4601 +         argv_printf( &argv,
4602 +                     "%s -6 addr add %s/%d dev %s",
4603 +                     iproute_path,
4604 +                     ifconfig_ipv6_local,
4605 +                     tt->netbits_ipv6,
4606 +                     actual
4607 +                     );
4608 +         argv_msg (M_INFO, &argv);
4609 +         openvpn_execve_check (&argv, es, S_FATAL, "Linux ip -6 addr add failed");
4610 +       }
4611 +      tt->did_ifconfig = true;
4612  #else
4613        if (tun)
4614         argv_printf (&argv,
4615 @@ -670,6 +742,18 @@
4616                           );
4617        argv_msg (M_INFO, &argv);
4618        openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed");
4619 +      if ( do_ipv6 )
4620 +       {
4621 +         argv_printf (&argv,
4622 +                         "%s %s inet6 add %s/%d",
4623 +                         IFCONFIG_PATH,
4624 +                         actual,
4625 +                         ifconfig_ipv6_local,
4626 +                         tt->netbits_ipv6
4627 +                         );
4628 +         argv_msg (M_INFO, &argv);
4629 +         openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig inet6 failed");
4630 +       }
4631        tt->did_ifconfig = true;
4632  
4633  #endif /*CONFIG_FEATURE_IPROUTE*/
4634 @@ -693,7 +777,7 @@
4635  
4636           argv_msg (M_INFO, &argv);
4637           if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed"))
4638 -           solaris_error_close (tt, es, actual);
4639 +           solaris_error_close (tt, es, actual, false);
4640  
4641           argv_printf (&argv,
4642                             "%s %s netmask 255.255.255.255",
4643 @@ -725,7 +809,53 @@
4644  
4645        argv_msg (M_INFO, &argv);
4646        if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed"))
4647 -       solaris_error_close (tt, es, actual);
4648 +       solaris_error_close (tt, es, actual, false);
4649 +
4650 +      if ( do_ipv6 )
4651 +        {
4652 +         argv_printf (&argv, "%s %s inet6 unplumb",
4653 +                           IFCONFIG_PATH, actual );
4654 +         argv_msg (M_INFO, &argv);
4655 +         openvpn_execve_check (&argv, es, 0, NULL);
4656 +
4657 +         if ( tt->type == DEV_TYPE_TUN )
4658 +          {
4659 +             argv_printf (&argv,
4660 +                           "%s %s inet6 plumb %s/%d %s up",
4661 +                           IFCONFIG_PATH,
4662 +                           actual,
4663 +                           ifconfig_ipv6_local,
4664 +                           tt->netbits_ipv6,
4665 +                           ifconfig_ipv6_remote
4666 +                           );
4667 +           }
4668 +         else                                          /* tap mode */
4669 +           {
4670 +             /* base IPv6 tap interface needs to be brought up first
4671 +              */
4672 +             argv_printf (&argv, "%s %s inet6 plumb up",
4673 +                           IFCONFIG_PATH, actual );
4674 +             argv_msg (M_INFO, &argv);
4675 +             if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 (prepare) failed"))
4676 +               solaris_error_close (tt, es, actual, true);
4677 +
4678 +             /* we might need to do "ifconfig %s inet6 auto-dhcp drop"
4679 +              * after the system has noticed the interface and fired up
4680 +              * the DHCPv6 client - but this takes quite a while, and the 
4681 +              * server will ignore the DHCPv6 packets anyway.  So we don't.
4682 +              */
4683 +
4684 +             /* static IPv6 addresses need to go to a subinterface (tap0:1)
4685 +              */
4686 +             argv_printf (&argv,
4687 +                           "%s %s inet6 addif %s/%d up",
4688 +                           IFCONFIG_PATH, actual,
4689 +                           ifconfig_ipv6_local, tt->netbits_ipv6 );
4690 +           }
4691 +         argv_msg (M_INFO, &argv);
4692 +         if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 failed"))
4693 +           solaris_error_close (tt, es, actual, true);
4694 +        }
4695  
4696        if (!tun && tt->topology == TOP_SUBNET)
4697         {
4698 @@ -787,10 +917,42 @@
4699                           );
4700        argv_msg (M_INFO, &argv);
4701        openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed");
4702 +      if ( do_ipv6 )
4703 +       {
4704 +         argv_printf (&argv,
4705 +                         "%s %s inet6 %s/%d",
4706 +                         IFCONFIG_PATH,
4707 +                         actual,
4708 +                         ifconfig_ipv6_local,
4709 +                         tt->netbits_ipv6
4710 +                         );
4711 +         argv_msg (M_INFO, &argv);
4712 +         openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig inet6 failed");
4713 +
4714 +         /* and, hooray, we explicitely need to add a route... */
4715 +         add_route_connected_v6_net(tt, es);
4716 +       }
4717        tt->did_ifconfig = true;
4718  
4719  #elif defined(TARGET_NETBSD)
4720  
4721 +/* whether or not NetBSD can do IPv6 can be seen by the availability of
4722 + * the TUNSIFHEAD ioctl() - see next TARGET_NETBSD block for more details
4723 + */
4724 +#ifdef TUNSIFHEAD
4725 +# define NETBSD_MULTI_AF
4726 +#endif
4727 +
4728 +      /* as on OpenBSD and Darwin, destroy and re-create tun<x> interface
4729 +       */
4730 +      argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, actual );
4731 +      argv_msg (M_INFO, &argv);
4732 +      openvpn_execve_check (&argv, es, 0, "NetBSD ifconfig destroy failed");
4733 +
4734 +      argv_printf (&argv, "%s %s create", IFCONFIG_PATH, actual );
4735 +      argv_msg (M_INFO, &argv);
4736 +      openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig create failed");
4737 +
4738        if (tun)
4739         argv_printf (&argv,
4740                           "%s %s %s %s mtu %d netmask 255.255.255.255 up",
4741 @@ -817,6 +979,27 @@
4742                           );
4743        argv_msg (M_INFO, &argv);
4744        openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed");
4745 +
4746 +      if ( do_ipv6 )
4747 +       {
4748 +#ifdef NETBSD_MULTI_AF
4749 +         argv_printf (&argv,
4750 +                         "%s %s inet6 %s/%d",
4751 +                         IFCONFIG_PATH,
4752 +                         actual,
4753 +                         ifconfig_ipv6_local,
4754 +                         tt->netbits_ipv6
4755 +                         );
4756 +         argv_msg (M_INFO, &argv);
4757 +         openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig inet6 failed");
4758 +
4759 +         /* and, hooray, we explicitely need to add a route... */
4760 +         add_route_connected_v6_net(tt, es);
4761 +#else
4762 +         msg( M_INFO, "no IPv6 support for tun interfaces on NetBSD before 4.0 (if your system is newer, recompile openvpn)" );
4763 +         tt->ipv6 = false;
4764 +#endif
4765 +       }
4766        tt->did_ifconfig = true;
4767  
4768  #elif defined(TARGET_DARWIN)
4769 @@ -882,6 +1065,22 @@
4770           add_route (&r, tt, 0, es);
4771         }
4772  
4773 +      if ( do_ipv6 )
4774 +       {
4775 +          argv_printf (&argv,
4776 +                              "%s %s inet6 %s/%d",
4777 +                              IFCONFIG_PATH,
4778 +                              actual,
4779 +                              ifconfig_ipv6_local,
4780 +                              tt->netbits_ipv6
4781 +                              );
4782 +         argv_msg (M_INFO, &argv);
4783 +         openvpn_execve_check (&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed");
4784 +
4785 +         /* and, hooray, we explicitely need to add a route... */
4786 +         add_route_connected_v6_net(tt, es);
4787 +       }
4788 +
4789  #elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
4790  
4791        /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
4792 @@ -920,6 +1119,19 @@
4793            add_route (&r, tt, 0, es);
4794          }
4795  
4796 +      if ( do_ipv6 )
4797 +       {
4798 +          argv_printf (&argv,
4799 +                              "%s %s inet6 %s/%d",
4800 +                              IFCONFIG_PATH,
4801 +                              actual,
4802 +                              ifconfig_ipv6_local,
4803 +                              tt->netbits_ipv6
4804 +                              );
4805 +         argv_msg (M_INFO, &argv);
4806 +         openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed");
4807 +       }
4808 +
4809  #elif defined (WIN32)
4810        {
4811         /*
4812 @@ -959,6 +1171,34 @@
4813         tt->did_ifconfig = true;
4814        }
4815  
4816 +    /* IPv6 always uses "netsh" interface */
4817 +    if ( do_ipv6 )
4818 +      {
4819 +       char * saved_actual;
4820 +
4821 +       if (!strcmp (actual, "NULL"))
4822 +         msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Win32 adapter, you must also specify --dev-node");
4823 +
4824 +       /* example: netsh interface ipv6 set address MyTap 2001:608:8003::d store=active */
4825 +       argv_printf (&argv,
4826 +                   "%s%sc interface ipv6 set address %s %s store=active",
4827 +                    get_win_sys_path(),
4828 +                    NETSH_PATH_SUFFIX,
4829 +                    actual,
4830 +                    ifconfig_ipv6_local );
4831 +
4832 +       netsh_command (&argv, 4);
4833 +
4834 +       /* explicit route needed */
4835 +       /* on windows, OpenVPN does ifconfig first, open_tun later, so
4836 +        * tt->actual_name might not yet be initialized, but routing code
4837 +        * needs to know interface name - point to "actual", restore later
4838 +        */
4839 +       saved_actual = tt->actual_name;
4840 +       tt->actual_name = (char*) actual;
4841 +       add_route_connected_v6_net(tt, es);
4842 +       tt->actual_name = saved_actual;
4843 +      }
4844  #else
4845        msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system.  You should ifconfig your TUN/TAP device manually or use an --up script.");
4846  #endif
4847 @@ -991,14 +1231,16 @@
4848  #ifndef WIN32
4849  static void
4850  open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
4851 -                 bool ipv6, bool ipv6_explicitly_supported, bool dynamic,
4852 +                 bool ipv6_explicitly_supported, bool dynamic,
4853                   struct tuntap *tt)
4854  {
4855    char tunname[256];
4856    char dynamic_name[256];
4857    bool dynamic_opened = false;
4858  
4859 -  ipv6_support (ipv6, ipv6_explicitly_supported, tt);
4860 +
4861 +  if ( tt->ipv6 && ! ipv6_explicitly_supported )
4862 +    msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
4863  
4864    if (tt->type == DEV_TYPE_NULL)
4865      {
4866 @@ -1094,16 +1336,16 @@
4867  #if !PEDANTIC
4868  
4869  void
4870 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
4871 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
4872  {
4873    struct ifreq ifr;
4874  
4875 -  /*
4876 -   * Set tt->ipv6 to true if
4877 -   * (a) we have the capability of supporting --tun-ipv6, and
4878 -   * (b) --tun-ipv6 was specified.
4879 +  /* warn if a very old linux version is used & --tun-ipv6 set
4880     */
4881 -  ipv6_support (ipv6, LINUX_IPV6, tt);
4882 +#if LINUX_IPV6 == 0
4883 +  if ( tt->ipv6 )
4884 +    msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
4885 +#endif
4886  
4887    /*
4888     * We handle --dev null specially, we do not open /dev/null for this.
4889 @@ -1222,9 +1464,9 @@
4890  #else
4891  
4892  void
4893 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
4894 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
4895  {
4896 -  open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt);
4897 +  open_tun_generic (dev, dev_type, dev_node, false, true, tt);
4898  }
4899  
4900  #endif /* HAVE_LINUX_IF_TUN_H */
4901 @@ -1244,7 +1486,7 @@
4902  #endif
4903  
4904  void
4905 -tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
4906 +tuncfg (const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
4907  {
4908    struct tuntap *tt;
4909  
4910 @@ -1252,7 +1494,7 @@
4911    clear_tuntap (tt);
4912    tt->type = dev_type_enum (dev, dev_type);
4913    tt->options = *options;
4914 -  open_tun (dev, dev_type, dev_node, ipv6, tt);
4915 +  open_tun (dev, dev_type, dev_node, tt);
4916    if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0)
4917      msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev);
4918    if (username != NULL)
4919 @@ -1395,7 +1637,7 @@
4920  #endif
4921  
4922  void
4923 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
4924 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
4925  {
4926    int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1;
4927    struct lifreq ifr;
4928 @@ -1406,8 +1648,11 @@
4929    bool is_tun;
4930    struct strioctl  strioc_if, strioc_ppa;
4931  
4932 -  ipv6_support (ipv6, true, tt);
4933 -  memset(&ifr, 0x0, sizeof(ifr));
4934 +  /* improved generic TUN/TAP driver from
4935 +   * http://www.whiteboard.ne.jp/~admin2/tuntap/
4936 +   * has IPv6 support
4937 +   */
4938 +  CLEAR(ifr);
4939  
4940    if (tt->type == DEV_TYPE_NULL)
4941      {
4942 @@ -1561,6 +1806,18 @@
4943  {
4944    if (tt)
4945      {
4946 +      /* IPv6 interfaces need to be 'manually' de-configured */
4947 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
4948 +       {
4949 +         struct argv argv;
4950 +         argv_init (&argv);
4951 +         argv_printf( &argv, "%s %s inet6 unplumb",
4952 +                      IFCONFIG_PATH, tt->actual_name );
4953 +         argv_msg (M_INFO, &argv);
4954 +         openvpn_execve_check (&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed");
4955 +         argv_reset (&argv);
4956 +       }
4957 +
4958        if (tt->ip_fd >= 0)
4959         {
4960            struct lifreq ifr;
4961 @@ -1613,11 +1870,20 @@
4962  }
4963  
4964  static void
4965 -solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual)
4966 +solaris_error_close (struct tuntap *tt, const struct env_set *es, 
4967 +                     const char *actual, bool unplumb_inet6 )
4968  {
4969    struct argv argv;
4970    argv_init (&argv);
4971  
4972 +  if (unplumb_inet6)
4973 +    {
4974 +      argv_printf( &argv, "%s %s inet6 unplumb",
4975 +                  IFCONFIG_PATH, actual );
4976 +      argv_msg (M_INFO, &argv);
4977 +      openvpn_execve_check (&argv, es, 0, "Solaris ifconfig inet6 unplumb failed");
4978 +    }
4979 +
4980    argv_printf (&argv,
4981                     "%s %s unplumb",
4982                     IFCONFIG_PATH,
4983 @@ -1674,9 +1940,9 @@
4984   */
4985  
4986  void
4987 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
4988 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
4989  {
4990 -  open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
4991 +  open_tun_generic (dev, dev_type, dev_node, true, true, tt);
4992  
4993    /* Enable multicast on the interface */
4994    if (tt->fd >= 0)
4995 @@ -1697,12 +1963,31 @@
4996      }
4997  }
4998  
4999 +/* the current way OpenVPN handles tun devices on OpenBSD leads to
5000 + * lingering tunX interfaces after close -> for a full cleanup, they
5001 + * need to be explicitely destroyed
5002 + */
5003 +
5004  void
5005  close_tun (struct tuntap* tt)
5006  {
5007    if (tt)
5008      {
5009 +      struct gc_arena gc = gc_new ();
5010 +      struct argv argv;
5011 +
5012 +      /* setup command, close tun dev (clears tt->actual_name!), run command
5013 +       */
5014 +
5015 +      argv_init (&argv);
5016 +      argv_printf (&argv, "%s %s destroy",
5017 +                          IFCONFIG_PATH, tt->actual_name);
5018 +
5019        close_tun_generic (tt);
5020 +
5021 +      argv_msg (M_INFO, &argv);
5022 +      openvpn_execve_check (&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)");
5023 +
5024        free (tt);
5025      }
5026  }
5027 @@ -1765,33 +2050,51 @@
5028  #elif defined(TARGET_NETBSD)
5029  
5030  /*
5031 - * NetBSD does not support IPv6 on tun out of the box,
5032 - * but there exists a patch. When this patch is applied,
5033 - * only two things are left to openvpn:
5034 - * 1. Activate multicasting (this has already been done
5035 - *    before by the kernel, but we make sure that nobody
5036 - *    has deactivated multicasting inbetween.
5037 - * 2. Deactivate "link layer mode" (otherwise NetBSD 
5038 - *    prepends the address family to the packet, and we
5039 - *    would run into the same trouble as with OpenBSD.
5040 + * NetBSD before 4.0 does not support IPv6 on tun out of the box,
5041 + * but there exists a patch (sys/net/if_tun.c, 1.79->1.80, see PR 32944).
5042 + *
5043 + * NetBSD 4.0 and up do, but we need to put the tun interface into
5044 + * "multi_af" mode, which will prepend the address family to all packets
5045 + * (same as OpenBSD and FreeBSD).  If this is not enabled, the kernel
5046 + * silently drops all IPv6 packets on output and gets confused on input.
5047 + *
5048 + * On earlier versions, multi_af is not available at all, so we have
5049 + * two different NetBSD code variants here :-(
5050 + *
5051   */
5052  
5053  void
5054 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
5055 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
5056  {
5057 -    open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
5058 +#ifdef NETBSD_MULTI_AF
5059 +    open_tun_generic (dev, dev_type, dev_node, true, true, tt);
5060 +#else
5061 +    open_tun_generic (dev, dev_type, dev_node, false, true, tt);
5062 +#endif
5063 +
5064      if (tt->fd >= 0)
5065        {
5066          int i = IFF_POINTOPOINT|IFF_MULTICAST;
5067          ioctl (tt->fd, TUNSIFMODE, &i);  /* multicast on */
5068          i = 0;
5069          ioctl (tt->fd, TUNSLMODE, &i);   /* link layer mode off */
5070 +
5071 +#ifdef NETBSD_MULTI_AF
5072 +        i = 1;
5073 +        if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0)        /* multi-af mode on */
5074 +         {
5075 +           msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
5076 +         }
5077 +#endif
5078        }
5079  }
5080  
5081  void
5082  close_tun (struct tuntap *tt)
5083  {
5084 +  /* TODO: we really should cleanup non-persistant tunX with 
5085 +   * "ifconfig tunX destroy" here...
5086 +   */
5087    if (tt)
5088      {
5089        close_tun_generic (tt);
5090 @@ -1799,6 +2102,65 @@
5091      }
5092  }
5093  
5094 +#ifdef NETBSD_MULTI_AF
5095 +
5096 +static inline int
5097 +netbsd_modify_read_write_return (int len)
5098 +{
5099 +  if (len > 0)
5100 +    return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
5101 +  else
5102 +    return len;
5103 +}
5104 +
5105 +int
5106 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
5107 +{
5108 +  if (tt->type == DEV_TYPE_TUN)
5109 +    {
5110 +      u_int32_t type;
5111 +      struct iovec iv[2];
5112 +      struct openvpn_iphdr *iph;
5113 +
5114 +      iph = (struct openvpn_iphdr *) buf;
5115 +
5116 +      if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6)
5117 +        type = htonl (AF_INET6);
5118 +      else 
5119 +        type = htonl (AF_INET);
5120 +
5121 +      iv[0].iov_base = (char *)&type;
5122 +      iv[0].iov_len = sizeof (type);
5123 +      iv[1].iov_base = buf;
5124 +      iv[1].iov_len = len;
5125 +
5126 +      return netbsd_modify_read_write_return (writev (tt->fd, iv, 2));
5127 +    }
5128 +  else
5129 +    return write (tt->fd, buf, len);
5130 +}
5131 +
5132 +int
5133 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
5134 +{
5135 +  if (tt->type == DEV_TYPE_TUN)
5136 +    {
5137 +      u_int32_t type;
5138 +      struct iovec iv[2];
5139 +
5140 +      iv[0].iov_base = (char *)&type;
5141 +      iv[0].iov_len = sizeof (type);
5142 +      iv[1].iov_base = buf;
5143 +      iv[1].iov_len = len;
5144 +
5145 +      return netbsd_modify_read_write_return (readv (tt->fd, iv, 2));
5146 +    }
5147 +  else
5148 +    return read (tt->fd, buf, len);
5149 +}
5150 +
5151 +#else  /* not NETBSD_MULTI_AF -> older code, IPv4 only */
5152 +
5153  int
5154  write_tun (struct tuntap* tt, uint8_t *buf, int len)
5155  {
5156 @@ -1810,6 +2172,7 @@
5157  {
5158      return read (tt->fd, buf, len);
5159  }
5160 +#endif /* NETBSD_MULTI_AF */
5161  
5162  #elif defined(TARGET_FREEBSD)
5163  
5164 @@ -1823,9 +2186,9 @@
5165  }
5166  
5167  void
5168 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
5169 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
5170  {
5171 -  open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
5172 +  open_tun_generic (dev, dev_type, dev_node, true, true, tt);
5173  
5174    if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN)
5175      {
5176 @@ -1911,9 +2274,9 @@
5177  }
5178  
5179  void
5180 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
5181 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
5182  {
5183 -  open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
5184 +  open_tun_generic (dev, dev_type, dev_node, true, true, tt);
5185  
5186    if (tt->fd >= 0)
5187      {
5188 @@ -1982,6 +2345,61 @@
5189      return read (tt->fd, buf, len);
5190  }
5191  
5192 +#elif defined(TARGET_DARWIN)
5193 +
5194 +/* Darwin (MacOS X) is mostly "just use the generic stuff", but there
5195 + * is always one caveat...:
5196 + *
5197 + * If IPv6 is configured, and the tun device is closed, the IPv6 address
5198 + * configured to the tun interface changes to a lingering /128 route
5199 + * pointing to lo0.  Need to unconfigure...  (observed on 10.5)
5200 + */
5201 +
5202 +void
5203 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
5204 +{
5205 +  open_tun_generic (dev, dev_type, dev_node, false, true, tt);
5206 +}
5207 +
5208 +void
5209 +close_tun (struct tuntap* tt)
5210 +{
5211 +  if (tt)
5212 +    {
5213 +      struct gc_arena gc = gc_new ();
5214 +      struct argv argv;
5215 +      argv_init (&argv);
5216 +
5217 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
5218 +       {
5219 +         const char * ifconfig_ipv6_local =
5220 +                               print_in6_addr (tt->local_ipv6, 0, &gc);
5221 +
5222 +          argv_printf (&argv, "%s delete -inet6 %s",
5223 +                              ROUTE_PATH, ifconfig_ipv6_local );
5224 +         argv_msg (M_INFO, &argv);
5225 +         openvpn_execve_check (&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)");
5226 +       }
5227 +
5228 +      close_tun_generic (tt);
5229 +      free (tt);
5230 +      argv_reset (&argv);
5231 +      gc_free (&gc);
5232 +    }
5233 +}
5234 +
5235 +int
5236 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
5237 +{
5238 +  return write (tt->fd, buf, len);
5239 +}
5240 +
5241 +int
5242 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
5243 +{
5244 +  return read (tt->fd, buf, len);
5245 +}
5246 +
5247  #elif defined(WIN32)
5248  
5249  int
5250 @@ -3967,7 +4385,7 @@
5251  }
5252  
5253  void
5254 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
5255 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
5256  {
5257    struct gc_arena gc = gc_new ();
5258    char device_path[256];
5259 @@ -3978,7 +4396,7 @@
5260  
5261    /*netcmd_semaphore_lock ();*/
5262  
5263 -  ipv6_support (ipv6, false, tt);
5264 +  msg( M_INFO, "open_tun, tt->ipv6=%d", tt->ipv6 );
5265  
5266    if (tt->type == DEV_TYPE_NULL)
5267      {
5268 @@ -4108,6 +4526,16 @@
5269        {
5270         msg( M_FATAL, "ERROR:  Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode.  Upgrade to Tap-Win32 9.9 (2.2.2 release or later) or use TAP mode", (int) info[0], (int) info[1] );
5271        }
5272 +
5273 +    /* usage of numeric constants is ugly, but this is really tied to
5274 +     * *this* version of the driver
5275 +     */
5276 +    if ( tt->ipv6 && tt->type == DEV_TYPE_TUN &&
5277 +         info[0] == 9 && info[1] < 8)
5278 +      {
5279 +       msg( M_INFO, "WARNING:  Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode.  IPv6 will be disabled.  Upgrade to Tap-Win32 9.8 (2.2-beta3 release or later) or use TAP mode to get IPv6", (int) info[0], (int) info[1] );
5280 +       tt->ipv6 = false;
5281 +      }
5282    }
5283  
5284    /* get driver MTU */
5285 @@ -4432,6 +4860,26 @@
5286  
5287    if (tt)
5288      {
5289 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
5290 +        {
5291 +         struct argv argv;
5292 +         argv_init (&argv);
5293 +
5294 +         /* remove route pointing to interface */
5295 +         delete_route_connected_v6_net(tt, NULL);
5296 +
5297 +         /* netsh interface ipv6 delete address \"%s\" %s */
5298 +         const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
5299 +         argv_printf (&argv,
5300 +                   "%s%sc interface ipv6 delete address %s %s",
5301 +                    get_win_sys_path(),
5302 +                    NETSH_PATH_SUFFIX,
5303 +                    tt->actual_name,
5304 +                    ifconfig_ipv6_local );
5305 +
5306 +         netsh_command (&argv, 1);
5307 +          argv_reset (&argv);
5308 +       }
5309  #if 1
5310        if (tt->ipapi_context_defined)
5311         {
5312 @@ -4535,9 +4983,9 @@
5313  #else /* generic */
5314  
5315  void
5316 -open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
5317 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
5318  {
5319 -  open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt);
5320 +  open_tun_generic (dev, dev_type, dev_node, false, true, tt);
5321  }
5322  
5323  void
5324 diff -durN openvpn-2.2.2.orig/tun.c~ openvpn-2.2.2/tun.c~
5325 --- openvpn-2.2.2.orig/tun.c~   1970-01-01 01:00:00.000000000 +0100
5326 +++ openvpn-2.2.2/tun.c~        2012-06-01 10:45:07.000000000 +0200
5327 @@ -0,0 +1,5003 @@
5328 +/*
5329 + *  OpenVPN -- An application to securely tunnel IP networks
5330 + *             over a single TCP/UDP port, with support for SSL/TLS-based
5331 + *             session authentication and key exchange,
5332 + *             packet encryption, packet authentication, and
5333 + *             packet compression.
5334 + *
5335 + *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
5336 + *
5337 + *  This program is free software; you can redistribute it and/or modify
5338 + *  it under the terms of the GNU General Public License version 2
5339 + *  as published by the Free Software Foundation.
5340 + *
5341 + *  This program is distributed in the hope that it will be useful,
5342 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
5343 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5344 + *  GNU General Public License for more details.
5345 + *
5346 + *  You should have received a copy of the GNU General Public License
5347 + *  along with this program (see the file COPYING included with this
5348 + *  distribution); if not, write to the Free Software Foundation, Inc.,
5349 + *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
5350 + */
5351 +
5352 +/*
5353 + * Support routines for configuring and accessing TUN/TAP
5354 + * virtual network adapters.
5355 + *
5356 + * This file is based on the TUN/TAP driver interface routines
5357 + * from VTun by Maxim Krasnyansky <max_mk@yahoo.com>.
5358 + */
5359 +
5360 +#include "syshead.h"
5361 +
5362 +#include "tun.h"
5363 +#include "fdmisc.h"
5364 +#include "common.h"
5365 +#include "misc.h"
5366 +#include "socket.h"
5367 +#include "manage.h"
5368 +#include "route.h"
5369 +#include "win32.h"
5370 +
5371 +#include "memdbg.h"
5372 +
5373 +#ifdef WIN32
5374 +
5375 +/* #define SIMULATE_DHCP_FAILED */       /* simulate bad DHCP negotiation */
5376 +
5377 +#define NI_TEST_FIRST  (1<<0)
5378 +#define NI_IP_NETMASK  (1<<1)
5379 +#define NI_OPTIONS     (1<<2)
5380 +
5381 +static void netsh_ifconfig (const struct tuntap_options *to,
5382 +                           const char *flex_name,
5383 +                           const in_addr_t ip,
5384 +                           const in_addr_t netmask,
5385 +                           const unsigned int flags);
5386 +static void netsh_command (const struct argv *a, int n);
5387 +
5388 +static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);
5389 +
5390 +#endif
5391 +
5392 +#ifdef TARGET_SOLARIS
5393 +static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6);
5394 +#include <stropts.h>
5395 +#endif
5396 +
5397 +bool
5398 +is_dev_type (const char *dev, const char *dev_type, const char *match_type)
5399 +{
5400 +  ASSERT (match_type);
5401 +  if (!dev)
5402 +    return false;
5403 +  if (dev_type)
5404 +    return !strcmp (dev_type, match_type);
5405 +  else
5406 +    return !strncmp (dev, match_type, strlen (match_type));
5407 +}
5408 +
5409 +int
5410 +dev_type_enum (const char *dev, const char *dev_type)
5411 +{
5412 +  if (is_dev_type (dev, dev_type, "tun"))
5413 +    return DEV_TYPE_TUN;
5414 +  else if (is_dev_type (dev, dev_type, "tap"))
5415 +    return DEV_TYPE_TAP;
5416 +  else if (is_dev_type (dev, dev_type, "null"))
5417 +    return DEV_TYPE_NULL;
5418 +  else
5419 +    return DEV_TYPE_UNDEF;
5420 +}
5421 +
5422 +const char *
5423 +dev_type_string (const char *dev, const char *dev_type)
5424 +{
5425 +  switch (dev_type_enum (dev, dev_type))
5426 +    {
5427 +    case DEV_TYPE_TUN:
5428 +      return "tun";
5429 +    case DEV_TYPE_TAP:
5430 +      return "tap";
5431 +    case DEV_TYPE_NULL:
5432 +      return "null";
5433 +    default:
5434 +      return "[unknown-dev-type]";
5435 +    }
5436 +}
5437 +
5438 +/*
5439 + * Try to predict the actual TUN/TAP device instance name,
5440 + * before the device is actually opened.
5441 + */
5442 +const char *
5443 +guess_tuntap_dev (const char *dev,
5444 +                 const char *dev_type,
5445 +                 const char *dev_node,
5446 +                 struct gc_arena *gc)
5447 +{
5448 +#ifdef WIN32
5449 +  const int dt = dev_type_enum (dev, dev_type);
5450 +  if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP)
5451 +    {
5452 +      return netsh_get_id (dev_node, gc);
5453 +    }
5454 +#endif
5455 +
5456 +  /* default case */
5457 +  return dev;
5458 +}
5459 +
5460 +
5461 +/* --ifconfig-nowarn disables some options sanity checking */
5462 +static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)";
5463 +
5464 +/*
5465 + * If !tun, make sure ifconfig_remote_netmask looks
5466 + *  like a netmask.
5467 + *
5468 + * If tun, make sure ifconfig_remote_netmask looks
5469 + *  like an IPv4 address.
5470 + */
5471 +static void
5472 +ifconfig_sanity_check (bool tun, in_addr_t addr, int topology)
5473 +{
5474 +  struct gc_arena gc = gc_new ();
5475 +  const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000);
5476 +  if (tun)
5477 +    {
5478 +      if (looks_like_netmask && (topology == TOP_NET30 || topology == TOP_P2P))
5479 +       msg (M_WARN, "WARNING: Since you are using --dev tun with a point-to-point topology, the second argument to --ifconfig must be an IP address.  You are using something (%s) that looks more like a netmask. %s",
5480 +            print_in_addr_t (addr, 0, &gc),
5481 +            ifconfig_warn_how_to_silence);
5482 +    }
5483 +  else /* tap */
5484 +    {
5485 +      if (!looks_like_netmask)
5486 +       msg (M_WARN, "WARNING: Since you are using --dev tap, the second argument to --ifconfig must be a netmask, for example something like 255.255.255.0. %s",
5487 +            ifconfig_warn_how_to_silence);
5488 +    }
5489 +  gc_free (&gc);
5490 +}
5491 +
5492 +/*
5493 + * For TAP-style devices, generate a broadcast address.
5494 + */
5495 +static in_addr_t
5496 +generate_ifconfig_broadcast_addr (in_addr_t local,
5497 +                                 in_addr_t netmask)
5498 +{
5499 +  return local | ~netmask;
5500 +}
5501 +
5502 +/*
5503 + * Check that --local and --remote addresses do not
5504 + * clash with ifconfig addresses or subnet.
5505 + */
5506 +static void
5507 +check_addr_clash (const char *name,
5508 +                 int type,
5509 +                 in_addr_t public,
5510 +                 in_addr_t local,
5511 +                 in_addr_t remote_netmask)
5512 +{
5513 +  struct gc_arena gc = gc_new ();
5514 +#if 0
5515 +  msg (M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, remote_netmask=%s",
5516 +       type,
5517 +       print_in_addr_t (public, 0, &gc),
5518 +       print_in_addr_t (local, 0, &gc),
5519 +       print_in_addr_t (remote_netmask, 0, &gc));
5520 +#endif
5521 +
5522 +  if (public)
5523 +    {
5524 +      if (type == DEV_TYPE_TUN)
5525 +       {
5526 +         const in_addr_t test_netmask = 0xFFFFFF00;
5527 +         const in_addr_t public_net = public & test_netmask;
5528 +         const in_addr_t local_net = local & test_netmask;
5529 +         const in_addr_t remote_net = remote_netmask & test_netmask;
5530 +
5531 +         if (public == local || public == remote_netmask)
5532 +           msg (M_WARN,
5533 +                "WARNING: --%s address [%s] conflicts with --ifconfig address pair [%s, %s]. %s",
5534 +                name,
5535 +                print_in_addr_t (public, 0, &gc),
5536 +                print_in_addr_t (local, 0, &gc),
5537 +                print_in_addr_t (remote_netmask, 0, &gc),
5538 +                ifconfig_warn_how_to_silence);
5539 +
5540 +         if (public_net == local_net || public_net == remote_net)
5541 +           msg (M_WARN,
5542 +                "WARNING: potential conflict between --%s address [%s] and --ifconfig address pair [%s, %s] -- this is a warning only that is triggered when local/remote addresses exist within the same /24 subnet as --ifconfig endpoints. %s",
5543 +                name,
5544 +                print_in_addr_t (public, 0, &gc),
5545 +                print_in_addr_t (local, 0, &gc),
5546 +                print_in_addr_t (remote_netmask, 0, &gc),
5547 +                ifconfig_warn_how_to_silence);
5548 +       }
5549 +      else if (type == DEV_TYPE_TAP)
5550 +       {
5551 +         const in_addr_t public_network = public & remote_netmask;
5552 +         const in_addr_t virtual_network = local & remote_netmask;
5553 +         if (public_network == virtual_network)
5554 +           msg (M_WARN,
5555 +                "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s, %s] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s",
5556 +                name,
5557 +                print_in_addr_t (public, 0, &gc),
5558 +                print_in_addr_t (local, 0, &gc),
5559 +                print_in_addr_t (remote_netmask, 0, &gc),
5560 +                ifconfig_warn_how_to_silence);
5561 +       }
5562 +    }
5563 +  gc_free (&gc);
5564 +}
5565 +
5566 +/*
5567 + * Issue a warning if ip/netmask (on the virtual IP network) conflicts with
5568 + * the settings on the local LAN.  This is designed to flag issues where
5569 + * (for example) the OpenVPN server LAN is running on 192.168.1.x, but then
5570 + * an OpenVPN client tries to connect from a public location that is also running
5571 + * off of a router set to 192.168.1.x.
5572 + */
5573 +void
5574 +check_subnet_conflict (const in_addr_t ip,
5575 +                      const in_addr_t netmask,
5576 +                      const char *prefix)
5577 +{
5578 +  struct gc_arena gc = gc_new ();
5579 +  in_addr_t lan_gw = 0;
5580 +  in_addr_t lan_netmask = 0;
5581 +
5582 +  if (get_default_gateway (&lan_gw, &lan_netmask))
5583 +    {
5584 +      const in_addr_t lan_network = lan_gw & lan_netmask; 
5585 +      const in_addr_t network = ip & netmask;
5586 +
5587 +      /* do the two subnets defined by network/netmask and lan_network/lan_netmask intersect? */
5588 +      if ((network & lan_netmask) == lan_network
5589 +         || (lan_network & netmask) == network)
5590 +       {
5591 +         msg (M_WARN, "WARNING: potential %s subnet conflict between local LAN [%s/%s] and remote VPN [%s/%s]",
5592 +              prefix,
5593 +              print_in_addr_t (lan_network, 0, &gc),
5594 +              print_in_addr_t (lan_netmask, 0, &gc),
5595 +              print_in_addr_t (network, 0, &gc),
5596 +              print_in_addr_t (netmask, 0, &gc));
5597 +       }
5598 +    }
5599 +  gc_free (&gc);
5600 +}
5601 +
5602 +void
5603 +warn_on_use_of_common_subnets (void)
5604 +{
5605 +  struct gc_arena gc = gc_new ();
5606 +  in_addr_t lan_gw = 0;
5607 +  in_addr_t lan_netmask = 0;
5608 +
5609 +  if (get_default_gateway (&lan_gw, &lan_netmask))
5610 +    {
5611 +      const in_addr_t lan_network = lan_gw & lan_netmask; 
5612 +      if (lan_network == 0xC0A80000 || lan_network == 0xC0A80100)
5613 +       msg (M_WARN, "NOTE: your local LAN uses the extremely common subnet address 192.168.0.x or 192.168.1.x.  Be aware that this might create routing conflicts if you connect to the VPN server from public locations such as internet cafes that use the same subnet.");
5614 +    }
5615 +  gc_free (&gc);
5616 +}
5617 +
5618 +/*
5619 + * Complain if --dev tap and --ifconfig is used on an OS for which
5620 + * we don't have a custom tap ifconfig template below.
5621 + */
5622 +static void
5623 +no_tap_ifconfig ()
5624 +{
5625 +  msg (M_FATAL, "Sorry but you cannot use --dev tap and --ifconfig together on this OS because I have not yet been programmed to understand the appropriate ifconfig syntax to use for TAP-style devices on this OS.  Your best alternative is to use an --up script and do the ifconfig command manually.");
5626 +}
5627 +
5628 +/*
5629 + * Return a string to be used for options compatibility check
5630 + * between peers.
5631 + */
5632 +const char *
5633 +ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, struct gc_arena *gc)
5634 +{
5635 +  struct buffer out = alloc_buf_gc (256, gc);
5636 +  if (tt->did_ifconfig_setup && !disable)
5637 +    {
5638 +      if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
5639 +       {
5640 +         buf_printf (&out, "%s %s",
5641 +                     print_in_addr_t (tt->local & tt->remote_netmask, 0, gc),
5642 +                     print_in_addr_t (tt->remote_netmask, 0, gc));
5643 +       }
5644 +      else if (tt->type == DEV_TYPE_TUN)
5645 +       {
5646 +         const char *l, *r;
5647 +         if (remote)
5648 +           {
5649 +             r = print_in_addr_t (tt->local, 0, gc);
5650 +             l = print_in_addr_t (tt->remote_netmask, 0, gc);
5651 +           }
5652 +         else
5653 +           {
5654 +             l = print_in_addr_t (tt->local, 0, gc);
5655 +             r = print_in_addr_t (tt->remote_netmask, 0, gc);
5656 +           }
5657 +         buf_printf (&out, "%s %s", r, l);
5658 +       }
5659 +      else
5660 +       buf_printf (&out, "[undef]");
5661 +    }
5662 +  return BSTR (&out);
5663 +}
5664 +
5665 +/*
5666 + * Return a status string describing wait state.
5667 + */
5668 +const char *
5669 +tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc)
5670 +{
5671 +  struct buffer out = alloc_buf_gc (64, gc);
5672 +  if (tt)
5673 +    {
5674 +      if (rwflags & EVENT_READ)
5675 +       {
5676 +         buf_printf (&out, "T%s",
5677 +                     (tt->rwflags_debug & EVENT_READ) ? "R" : "r");
5678 +#ifdef WIN32
5679 +         buf_printf (&out, "%s",
5680 +                     overlapped_io_state_ascii (&tt->reads));
5681 +#endif
5682 +       }
5683 +      if (rwflags & EVENT_WRITE)
5684 +       {
5685 +         buf_printf (&out, "T%s",
5686 +                     (tt->rwflags_debug & EVENT_WRITE) ? "W" : "w");
5687 +#ifdef WIN32
5688 +         buf_printf (&out, "%s",
5689 +                     overlapped_io_state_ascii (&tt->writes));
5690 +#endif
5691 +       }
5692 +    }
5693 +  else
5694 +    {
5695 +      buf_printf (&out, "T?");
5696 +    }
5697 +  return BSTR (&out);
5698 +}
5699 +
5700 +/*
5701 + * Return true for point-to-point topology, false for subnet topology
5702 + */
5703 +bool
5704 +is_tun_p2p (const struct tuntap *tt)
5705 +{
5706 +  bool tun = false;
5707 +
5708 +  if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
5709 +    tun = false;
5710 +  else if (tt->type == DEV_TYPE_TUN)
5711 +    tun = true;
5712 +  else
5713 +    msg (M_FATAL, "Error: problem with tun vs. tap setting"); /* JYFIXME -- needs to be caught earlier, in init_tun? */
5714 +
5715 +  return tun;
5716 +}
5717 +
5718 +/*
5719 + * Init tun/tap object.
5720 + *
5721 + * Set up tuntap structure for ifconfig,
5722 + * but don't execute yet.
5723 + */
5724 +struct tuntap *
5725 +init_tun (const char *dev,       /* --dev option */
5726 +         const char *dev_type,  /* --dev-type option */
5727 +         int topology,          /* one of the TOP_x values */
5728 +         const char *ifconfig_local_parm,          /* --ifconfig parm 1 */
5729 +         const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
5730 +         const char *ifconfig_ipv6_local_parm,     /* --ifconfig parm 1 IPv6 */
5731 +         const char *ifconfig_ipv6_remote_parm,    /* --ifconfig parm 2 IPv6 */
5732 +         in_addr_t local_public,
5733 +         in_addr_t remote_public,
5734 +         const bool strict_warn,
5735 +         struct env_set *es)
5736 +{
5737 +  struct gc_arena gc = gc_new ();
5738 +  struct tuntap *tt;
5739 +
5740 +  ALLOC_OBJ (tt, struct tuntap);
5741 +  clear_tuntap (tt);
5742 +
5743 +  tt->type = dev_type_enum (dev, dev_type);
5744 +  tt->topology = topology;
5745 +
5746 +  if (ifconfig_local_parm && ifconfig_remote_netmask_parm)
5747 +    {
5748 +      bool tun = false;
5749 +      const char *ifconfig_local = NULL;
5750 +      const char *ifconfig_remote_netmask = NULL;
5751 +      const char *ifconfig_broadcast = NULL;
5752 +
5753 +      /*
5754 +       * We only handle TUN/TAP devices here, not --dev null devices.
5755 +       */
5756 +      tun = is_tun_p2p (tt);
5757 +
5758 +      /*
5759 +       * Convert arguments to binary IPv4 addresses.
5760 +       */
5761 +
5762 +      tt->local = getaddr (
5763 +                          GETADDR_RESOLVE
5764 +                          | GETADDR_HOST_ORDER
5765 +                          | GETADDR_FATAL_ON_SIGNAL
5766 +                          | GETADDR_FATAL,
5767 +                          ifconfig_local_parm,
5768 +                          0,
5769 +                          NULL,
5770 +                          NULL);
5771 +
5772 +      tt->remote_netmask = getaddr (
5773 +                                   (tun ? GETADDR_RESOLVE : 0)
5774 +                                   | GETADDR_HOST_ORDER
5775 +                                   | GETADDR_FATAL_ON_SIGNAL
5776 +                                   | GETADDR_FATAL,
5777 +                                   ifconfig_remote_netmask_parm,
5778 +                                   0,
5779 +                                   NULL,
5780 +                                   NULL);
5781 +
5782 +      /*
5783 +       * Look for common errors in --ifconfig parms
5784 +       */
5785 +      if (strict_warn)
5786 +       {
5787 +         ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology);
5788 +
5789 +         /*
5790 +          * If local_public or remote_public addresses are defined,
5791 +          * make sure they do not clash with our virtual subnet.
5792 +          */
5793 +
5794 +         check_addr_clash ("local",
5795 +                           tt->type,
5796 +                           local_public,
5797 +                           tt->local,
5798 +                           tt->remote_netmask);
5799 +
5800 +         check_addr_clash ("remote",
5801 +                           tt->type,
5802 +                           remote_public,
5803 +                           tt->local,
5804 +                           tt->remote_netmask);
5805 +
5806 +         if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
5807 +           check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter");
5808 +         else if (tt->type == DEV_TYPE_TUN)
5809 +           check_subnet_conflict (tt->local, ~0, "TUN/TAP adapter");
5810 +       }
5811 +
5812 +      /*
5813 +       * Set ifconfig parameters
5814 +       */
5815 +      ifconfig_local = print_in_addr_t (tt->local, 0, &gc);
5816 +      ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);
5817 +
5818 +      /*
5819 +       * If TAP-style interface, generate broadcast address.
5820 +       */
5821 +      if (!tun)
5822 +       {
5823 +         tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask);
5824 +         ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc);
5825 +       }
5826 +
5827 +      /*
5828 +       * Set environmental variables with ifconfig parameters.
5829 +       */
5830 +      if (es)
5831 +       {
5832 +         setenv_str (es, "ifconfig_local", ifconfig_local);
5833 +         if (tun)
5834 +           {
5835 +             setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask);
5836 +           }
5837 +         else
5838 +           {
5839 +             setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask);
5840 +             setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast);
5841 +           }
5842 +       }
5843 +
5844 +      tt->did_ifconfig_setup = true;
5845 +    }
5846 +
5847 +  if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm)
5848 +    {
5849 +      const char *ifconfig_ipv6_local = NULL;
5850 +      const char *ifconfig_ipv6_remote = NULL;
5851 +
5852 +      /*
5853 +       * Convert arguments to binary IPv6 addresses.
5854 +       */
5855 +
5856 +      if ( inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 ||
5857 +           inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1 ) 
5858 +       {
5859 +         msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm );
5860 +       }
5861 +      tt->netbits_ipv6 = 64;
5862 +
5863 +      /*
5864 +       * Set ifconfig parameters
5865 +       */
5866 +      ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
5867 +      ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
5868 +
5869 +      /*
5870 +       * Set environmental variables with ifconfig parameters.
5871 +       */
5872 +      if (es)
5873 +       {
5874 +         setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local);
5875 +         setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote);
5876 +       }
5877 +      tt->did_ifconfig_ipv6_setup = true;
5878 +    }
5879 +
5880 +  gc_free (&gc);
5881 +  return tt;
5882 +}
5883 +
5884 +/*
5885 + * Platform specific tun initializations
5886 + */
5887 +void
5888 +init_tun_post (struct tuntap *tt,
5889 +              const struct frame *frame,
5890 +              const struct tuntap_options *options)
5891 +{
5892 +  tt->options = *options;
5893 +#ifdef WIN32
5894 +  overlapped_io_init (&tt->reads, frame, FALSE, true);
5895 +  overlapped_io_init (&tt->writes, frame, TRUE, true);
5896 +  tt->rw_handle.read = tt->reads.overlapped.hEvent;
5897 +  tt->rw_handle.write = tt->writes.overlapped.hEvent;
5898 +  tt->adapter_index = ~0;
5899 +#endif
5900 +}
5901 +
5902 +#if defined(TARGET_WIN32) || \
5903 +    defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD)
5904 +
5905 +/* some of the platforms will auto-add a "network route" pointing
5906 + * to the interface on "ifconfig tunX 2001:db8::1/64", others need
5907 + * an extra call to "route add..."
5908 + * -> helper function to simplify code below
5909 + */
5910 +void add_route_connected_v6_net(struct tuntap * tt,
5911 +                               const struct env_set *es)
5912 +{
5913 +    struct route_ipv6 r6;
5914 +
5915 +    r6.defined = true;
5916 +    r6.network = tt->local_ipv6;
5917 +    r6.netbits = tt->netbits_ipv6;
5918 +    r6.gateway = tt->local_ipv6;
5919 +    add_route_ipv6 (&r6, tt, 0, es);
5920 +}
5921 +
5922 +void delete_route_connected_v6_net(struct tuntap * tt,
5923 +                                  const struct env_set *es)
5924 +{
5925 +    struct route_ipv6 r6;
5926 +
5927 +    r6.defined = true;
5928 +    r6.network = tt->local_ipv6;
5929 +    r6.netbits = tt->netbits_ipv6;
5930 +    r6.gateway = tt->local_ipv6;
5931 +    delete_route_ipv6 (&r6, tt, 0, es);
5932 +}
5933 +#endif
5934 +
5935 +
5936 +/* execute the ifconfig command through the shell */
5937 +void
5938 +do_ifconfig (struct tuntap *tt,
5939 +            const char *actual,    /* actual device name */
5940 +            int tun_mtu,
5941 +            const struct env_set *es)
5942 +{
5943 +  struct gc_arena gc = gc_new ();
5944 +
5945 +  if (tt->did_ifconfig_setup)
5946 +    {
5947 +      bool tun = false;
5948 +      const char *ifconfig_local = NULL;
5949 +      const char *ifconfig_remote_netmask = NULL;
5950 +      const char *ifconfig_broadcast = NULL;
5951 +      const char *ifconfig_ipv6_local = NULL;
5952 +      const char *ifconfig_ipv6_remote = NULL;
5953 +      bool do_ipv6 = false;
5954 +      struct argv argv;
5955 +
5956 +      argv_init (&argv);
5957 +
5958 +      msg( M_INFO, "do_ifconfig, tt->ipv6=%d, tt->did_ifconfig_ipv6_setup=%d",
5959 +                  tt->ipv6, tt->did_ifconfig_ipv6_setup );
5960 +
5961 +      /*
5962 +       * We only handle TUN/TAP devices here, not --dev null devices.
5963 +       */
5964 +      tun = is_tun_p2p (tt);
5965 +
5966 +      /*
5967 +       * Set ifconfig parameters
5968 +       */
5969 +      ifconfig_local = print_in_addr_t (tt->local, 0, &gc);
5970 +      ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);
5971 +
5972 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
5973 +        {
5974 +         ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
5975 +         ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
5976 +         do_ipv6 = true;
5977 +       }
5978 +
5979 +      /*
5980 +       * If TAP-style device, generate broadcast address.
5981 +       */
5982 +      if (!tun)
5983 +       ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc);
5984 +
5985 +#ifdef ENABLE_MANAGEMENT
5986 +  if (management)
5987 +    {
5988 +      management_set_state (management,
5989 +                           OPENVPN_STATE_ASSIGN_IP,
5990 +                           NULL,
5991 +                           tt->local,
5992 +                           0);
5993 +    }
5994 +#endif
5995 +
5996 +
5997 +#if defined(TARGET_LINUX)
5998 +#ifdef CONFIG_FEATURE_IPROUTE
5999 +       /*
6000 +        * Set the MTU for the device
6001 +        */
6002 +       argv_printf (&argv,
6003 +                         "%s link set dev %s up mtu %d",
6004 +                         iproute_path,
6005 +                         actual,
6006 +                         tun_mtu
6007 +                         );
6008 +         argv_msg (M_INFO, &argv);
6009 +         openvpn_execve_check (&argv, es, S_FATAL, "Linux ip link set failed");
6010 +
6011 +       if (tun) {
6012 +
6013 +               /*
6014 +                * Set the address for the device
6015 +                */
6016 +               argv_printf (&argv,
6017 +                                 "%s addr add dev %s local %s peer %s",
6018 +                                 iproute_path,
6019 +                                 actual,
6020 +                                 ifconfig_local,
6021 +                                 ifconfig_remote_netmask
6022 +                                 );
6023 +                 argv_msg (M_INFO, &argv);
6024 +                 openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed");
6025 +       } else {
6026 +               argv_printf (&argv,
6027 +                                 "%s addr add dev %s %s/%d broadcast %s",
6028 +                                 iproute_path,
6029 +                                 actual,
6030 +                                 ifconfig_local,
6031 +                                 count_netmask_bits(ifconfig_remote_netmask),
6032 +                                 ifconfig_broadcast
6033 +                                 );
6034 +                 argv_msg (M_INFO, &argv);
6035 +                 openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed");
6036 +       }
6037 +      if ( do_ipv6 )
6038 +       {
6039 +         argv_printf( &argv,
6040 +                     "%s -6 addr add %s/%d dev %s",
6041 +                     iproute_path,
6042 +                     ifconfig_ipv6_local,
6043 +                     tt->netbits_ipv6,
6044 +                     actual
6045 +                     );
6046 +         argv_msg (M_INFO, &argv);
6047 +         openvpn_execve_check (&argv, es, S_FATAL, "Linux ip -6 addr add failed");
6048 +       }
6049 +      tt->did_ifconfig = true;
6050 +#else
6051 +      if (tun)
6052 +       argv_printf (&argv,
6053 +                         "%s %s %s pointopoint %s mtu %d",
6054 +                         IFCONFIG_PATH,
6055 +                         actual,
6056 +                         ifconfig_local,
6057 +                         ifconfig_remote_netmask,
6058 +                         tun_mtu
6059 +                         );
6060 +      else
6061 +       argv_printf (&argv,
6062 +                         "%s %s %s netmask %s mtu %d broadcast %s",
6063 +                         IFCONFIG_PATH,
6064 +                         actual,
6065 +                         ifconfig_local,
6066 +                         ifconfig_remote_netmask,
6067 +                         tun_mtu,
6068 +                         ifconfig_broadcast
6069 +                         );
6070 +      argv_msg (M_INFO, &argv);
6071 +      openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed");
6072 +      if ( do_ipv6 )
6073 +       {
6074 +         argv_printf (&argv,
6075 +                         "%s %s inet6 add %s/%d",
6076 +                         IFCONFIG_PATH,
6077 +                         actual,
6078 +                         ifconfig_ipv6_local,
6079 +                         tt->netbits_ipv6
6080 +                         );
6081 +         argv_msg (M_INFO, &argv);
6082 +         openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig inet6 failed");
6083 +       }
6084 +      tt->did_ifconfig = true;
6085 +
6086 +#endif /*CONFIG_FEATURE_IPROUTE*/
6087 +#elif defined(TARGET_SOLARIS)
6088 +
6089 +      /* Solaris 2.6 (and 7?) cannot set all parameters in one go...
6090 +       * example:
6091 +       *    ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 up
6092 +       *    ifconfig tun2 netmask 255.255.255.255
6093 +       */
6094 +      if (tun)
6095 +       {
6096 +         argv_printf (&argv,
6097 +                           "%s %s %s %s mtu %d up",
6098 +                           IFCONFIG_PATH,
6099 +                           actual,
6100 +                           ifconfig_local,
6101 +                           ifconfig_remote_netmask,
6102 +                           tun_mtu
6103 +                           );
6104 +
6105 +         argv_msg (M_INFO, &argv);
6106 +         if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed"))
6107 +           solaris_error_close (tt, es, actual, false);
6108 +
6109 +         argv_printf (&argv,
6110 +                           "%s %s netmask 255.255.255.255",
6111 +                           IFCONFIG_PATH,
6112 +                           actual
6113 +                           );
6114 +       }
6115 +      else
6116 +        if (tt->topology == TOP_SUBNET)
6117 +       {
6118 +          argv_printf (&argv,
6119 +                              "%s %s %s %s netmask %s mtu %d up",
6120 +                              IFCONFIG_PATH,
6121 +                              actual,
6122 +                              ifconfig_local,
6123 +                              ifconfig_local,
6124 +                              ifconfig_remote_netmask,
6125 +                              tun_mtu
6126 +                              );
6127 +       }
6128 +        else
6129 +          argv_printf (&argv,
6130 +                            " %s %s %s netmask %s broadcast + up",
6131 +                            IFCONFIG_PATH,
6132 +                            actual,
6133 +                            ifconfig_local,
6134 +                            ifconfig_remote_netmask
6135 +                            );
6136 +
6137 +      argv_msg (M_INFO, &argv);
6138 +      if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed"))
6139 +       solaris_error_close (tt, es, actual, false);
6140 +
6141 +      if ( do_ipv6 )
6142 +        {
6143 +         argv_printf (&argv, "%s %s inet6 unplumb",
6144 +                           IFCONFIG_PATH, actual );
6145 +         argv_msg (M_INFO, &argv);
6146 +         openvpn_execve_check (&argv, es, 0, NULL);
6147 +
6148 +         if ( tt->type == DEV_TYPE_TUN )
6149 +          {
6150 +             argv_printf (&argv,
6151 +                           "%s %s inet6 plumb %s/%d %s up",
6152 +                           IFCONFIG_PATH,
6153 +                           actual,
6154 +                           ifconfig_ipv6_local,
6155 +                           tt->netbits_ipv6,
6156 +                           ifconfig_ipv6_remote
6157 +                           );
6158 +           }
6159 +         else                                          /* tap mode */
6160 +           {
6161 +             /* base IPv6 tap interface needs to be brought up first
6162 +              */
6163 +             argv_printf (&argv, "%s %s inet6 plumb up",
6164 +                           IFCONFIG_PATH, actual );
6165 +             argv_msg (M_INFO, &argv);
6166 +             if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 (prepare) failed"))
6167 +               solaris_error_close (tt, es, actual, true);
6168 +
6169 +             /* we might need to do "ifconfig %s inet6 auto-dhcp drop"
6170 +              * after the system has noticed the interface and fired up
6171 +              * the DHCPv6 client - but this takes quite a while, and the 
6172 +              * server will ignore the DHCPv6 packets anyway.  So we don't.
6173 +              */
6174 +
6175 +             /* static IPv6 addresses need to go to a subinterface (tap0:1)
6176 +              */
6177 +             argv_printf (&argv,
6178 +                           "%s %s inet6 addif %s/%d up",
6179 +                           IFCONFIG_PATH, actual,
6180 +                           ifconfig_ipv6_local, tt->netbits_ipv6 );
6181 +           }
6182 +         argv_msg (M_INFO, &argv);
6183 +         if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 failed"))
6184 +           solaris_error_close (tt, es, actual, true);
6185 +        }
6186 +
6187 +      if (!tun && tt->topology == TOP_SUBNET)
6188 +       {
6189 +         /* Add a network route for the local tun interface */
6190 +         struct route r;
6191 +         CLEAR (r);      
6192 +         r.defined = true;       
6193 +         r.network = tt->local & tt->remote_netmask;
6194 +         r.netmask = tt->remote_netmask;
6195 +         r.gateway = tt->local;  
6196 +         r.metric_defined = true;
6197 +         r.metric = 0;
6198 +         add_route (&r, tt, 0, es);
6199 +       }
6200 +
6201 +      tt->did_ifconfig = true;
6202 +
6203 +#elif defined(TARGET_OPENBSD)
6204 +
6205 +      /*
6206 +       * OpenBSD tun devices appear to be persistent by default.  It seems in order
6207 +       * to make this work correctly, we need to delete the previous instance
6208 +       * (if it exists), and re-ifconfig.  Let me know if you know a better way.
6209 +       */
6210 +
6211 +      argv_printf (&argv,
6212 +                       "%s %s destroy",
6213 +                       IFCONFIG_PATH,
6214 +                       actual);
6215 +      argv_msg (M_INFO, &argv);
6216 +      openvpn_execve_check (&argv, es, 0, NULL);
6217 +      argv_printf (&argv,
6218 +                       "%s %s create",
6219 +                       IFCONFIG_PATH,
6220 +                       actual);
6221 +      argv_msg (M_INFO, &argv);
6222 +      openvpn_execve_check (&argv, es, 0, NULL);
6223 +      msg (M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure");
6224 +
6225 +      /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
6226 +      if (tun)
6227 +       argv_printf (&argv,
6228 +                         "%s %s %s %s mtu %d netmask 255.255.255.255 up",
6229 +                         IFCONFIG_PATH,
6230 +                         actual,
6231 +                         ifconfig_local,
6232 +                         ifconfig_remote_netmask,
6233 +                         tun_mtu
6234 +                         );
6235 +      else
6236 +       argv_printf (&argv,
6237 +                         "%s %s %s netmask %s mtu %d broadcast %s link0",
6238 +                         IFCONFIG_PATH,
6239 +                         actual,
6240 +                         ifconfig_local,
6241 +                         ifconfig_remote_netmask,
6242 +                         tun_mtu,
6243 +                         ifconfig_broadcast
6244 +                         );
6245 +      argv_msg (M_INFO, &argv);
6246 +      openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed");
6247 +      if ( do_ipv6 )
6248 +       {
6249 +         argv_printf (&argv,
6250 +                         "%s %s inet6 %s/%d",
6251 +                         IFCONFIG_PATH,
6252 +                         actual,
6253 +                         ifconfig_ipv6_local,
6254 +                         tt->netbits_ipv6
6255 +                         );
6256 +         argv_msg (M_INFO, &argv);
6257 +         openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig inet6 failed");
6258 +
6259 +         /* and, hooray, we explicitely need to add a route... */
6260 +         add_route_connected_v6_net(tt, es);
6261 +       }
6262 +      tt->did_ifconfig = true;
6263 +
6264 +#elif defined(TARGET_NETBSD)
6265 +
6266 +/* whether or not NetBSD can do IPv6 can be seen by the availability of
6267 + * the TUNSIFHEAD ioctl() - see next TARGET_NETBSD block for more details
6268 + */
6269 +#ifdef TUNSIFHEAD
6270 +# define NETBSD_MULTI_AF
6271 +#endif
6272 +
6273 +      /* as on OpenBSD and Darwin, destroy and re-create tun<x> interface
6274 +       */
6275 +      argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, actual );
6276 +      argv_msg (M_INFO, &argv);
6277 +      openvpn_execve_check (&argv, es, 0, "NetBSD ifconfig destroy failed");
6278 +
6279 +      argv_printf (&argv, "%s %s create", IFCONFIG_PATH, actual );
6280 +      argv_msg (M_INFO, &argv);
6281 +      openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig create failed");
6282 +
6283 +      if (tun)
6284 +       argv_printf (&argv,
6285 +                         "%s %s %s %s mtu %d netmask 255.255.255.255 up",
6286 +                         IFCONFIG_PATH,
6287 +                         actual,
6288 +                         ifconfig_local,
6289 +                         ifconfig_remote_netmask,
6290 +                         tun_mtu
6291 +                         );
6292 +      else
6293 +      /*
6294 +       * NetBSD has distinct tun and tap devices
6295 +       * so we don't need the "link0" extra parameter to specify we want to do 
6296 +       * tunneling at the ethernet level
6297 +       */
6298 +               argv_printf (&argv,
6299 +                         "%s %s %s netmask %s mtu %d broadcast %s",
6300 +                         IFCONFIG_PATH,
6301 +                         actual,
6302 +                         ifconfig_local,
6303 +                         ifconfig_remote_netmask,
6304 +                         tun_mtu,
6305 +                         ifconfig_broadcast
6306 +                         );
6307 +      argv_msg (M_INFO, &argv);
6308 +      openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed");
6309 +
6310 +      if ( do_ipv6 )
6311 +       {
6312 +#ifdef NETBSD_MULTI_AF
6313 +         argv_printf (&argv,
6314 +                         "%s %s inet6 %s/%d",
6315 +                         IFCONFIG_PATH,
6316 +                         actual,
6317 +                         ifconfig_ipv6_local,
6318 +                         tt->netbits_ipv6
6319 +                         );
6320 +         argv_msg (M_INFO, &argv);
6321 +         openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig inet6 failed");
6322 +
6323 +         /* and, hooray, we explicitely need to add a route... */
6324 +         add_route_connected_v6_net(tt, es);
6325 +#else
6326 +         msg( M_INFO, "no IPv6 support for tun interfaces on NetBSD before 4.0 (if your system is newer, recompile openvpn)" );
6327 +         tt->ipv6 = false;
6328 +#endif
6329 +       }
6330 +      tt->did_ifconfig = true;
6331 +
6332 +#elif defined(TARGET_DARWIN)
6333 +
6334 +      /*
6335 +       * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD...
6336 +       */
6337 +
6338 +      argv_printf (&argv,
6339 +                       "%s %s delete",
6340 +                       IFCONFIG_PATH,
6341 +                       actual);
6342 +      argv_msg (M_INFO, &argv);
6343 +      openvpn_execve_check (&argv, es, 0, NULL);
6344 +      msg (M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure");
6345 +
6346 +
6347 +      /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
6348 +      if (tun)
6349 +       argv_printf (&argv,
6350 +                         "%s %s %s %s mtu %d netmask 255.255.255.255 up",
6351 +                         IFCONFIG_PATH,
6352 +                         actual,
6353 +                         ifconfig_local,
6354 +                         ifconfig_remote_netmask,
6355 +                         tun_mtu
6356 +                         );
6357 +      else
6358 +        {
6359 +          if (tt->topology == TOP_SUBNET)
6360 +           argv_printf (&argv,
6361 +                             "%s %s %s %s netmask %s mtu %d up",
6362 +                             IFCONFIG_PATH,
6363 +                             actual,
6364 +                             ifconfig_local,
6365 +                             ifconfig_local,
6366 +                             ifconfig_remote_netmask,
6367 +                             tun_mtu
6368 +                             );
6369 +         else
6370 +           argv_printf (&argv,
6371 +                             "%s %s %s netmask %s mtu %d up",
6372 +                             IFCONFIG_PATH,
6373 +                             actual,
6374 +                             ifconfig_local,
6375 +                             ifconfig_remote_netmask,
6376 +                             tun_mtu
6377 +                             );
6378 +       }
6379 +      argv_msg (M_INFO, &argv);
6380 +      openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ifconfig failed");
6381 +      tt->did_ifconfig = true;
6382 +
6383 +      /* Add a network route for the local tun interface */
6384 +      if (!tun && tt->topology == TOP_SUBNET)
6385 +       {
6386 +         struct route r;
6387 +         CLEAR (r);
6388 +         r.defined = true;
6389 +         r.network = tt->local & tt->remote_netmask;
6390 +         r.netmask = tt->remote_netmask;
6391 +         r.gateway = tt->local;
6392 +         add_route (&r, tt, 0, es);
6393 +       }
6394 +
6395 +      if ( do_ipv6 )
6396 +       {
6397 +          argv_printf (&argv,
6398 +                              "%s %s inet6 %s/%d",
6399 +                              IFCONFIG_PATH,
6400 +                              actual,
6401 +                              ifconfig_ipv6_local,
6402 +                              tt->netbits_ipv6
6403 +                              );
6404 +         argv_msg (M_INFO, &argv);
6405 +         openvpn_execve_check (&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed");
6406 +
6407 +         /* and, hooray, we explicitely need to add a route... */
6408 +         add_route_connected_v6_net(tt, es);
6409 +       }
6410 +
6411 +#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
6412 +
6413 +      /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
6414 +      if (tun)
6415 +       argv_printf (&argv,
6416 +                         "%s %s %s %s mtu %d netmask 255.255.255.255 up",
6417 +                         IFCONFIG_PATH,
6418 +                         actual,
6419 +                         ifconfig_local,
6420 +                         ifconfig_remote_netmask,
6421 +                         tun_mtu
6422 +                         );
6423 +      else
6424 +       argv_printf (&argv,
6425 +                     "%s %s %s netmask %s mtu %d up",
6426 +                              IFCONFIG_PATH,
6427 +                              actual,
6428 +                              ifconfig_local,
6429 +                              ifconfig_remote_netmask,
6430 +                              tun_mtu
6431 +                              );
6432 +       
6433 +      argv_msg (M_INFO, &argv);
6434 +      openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig failed");
6435 +      tt->did_ifconfig = true;
6436 +
6437 +       /* Add a network route for the local tun interface */
6438 +      if (!tun && tt->topology == TOP_SUBNET)
6439 +        {               
6440 +          struct route r;
6441 +          CLEAR (r);      
6442 +          r.defined = true;       
6443 +          r.network = tt->local & tt->remote_netmask;
6444 +          r.netmask = tt->remote_netmask;
6445 +          r.gateway = tt->local;  
6446 +          add_route (&r, tt, 0, es);
6447 +        }
6448 +
6449 +      if ( do_ipv6 )
6450 +       {
6451 +          argv_printf (&argv,
6452 +                              "%s %s inet6 %s/%d",
6453 +                              IFCONFIG_PATH,
6454 +                              actual,
6455 +                              ifconfig_ipv6_local,
6456 +                              tt->netbits_ipv6
6457 +                              );
6458 +         argv_msg (M_INFO, &argv);
6459 +         openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed");
6460 +       }
6461 +
6462 +#elif defined (WIN32)
6463 +      {
6464 +       /*
6465 +        * Make sure that both ifconfig addresses are part of the
6466 +        * same .252 subnet.
6467 +        */
6468 +       if (tun)
6469 +         {
6470 +           verify_255_255_255_252 (tt->local, tt->remote_netmask);
6471 +           tt->adapter_netmask = ~3;
6472 +         }
6473 +       else
6474 +         {
6475 +           tt->adapter_netmask = tt->remote_netmask;
6476 +         }
6477 +
6478 +       switch (tt->options.ip_win32_type)
6479 +         {
6480 +         case IPW32_SET_MANUAL:
6481 +           msg (M_INFO, "******** NOTE:  Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)",
6482 +                actual,
6483 +                ifconfig_local,
6484 +                print_in_addr_t (tt->adapter_netmask, 0, &gc));
6485 +           break;
6486 +         case IPW32_SET_NETSH:
6487 +           if (!strcmp (actual, "NULL"))
6488 +             msg (M_FATAL, "Error: When using --ip-win32 netsh, if you have more than one TAP-Win32 adapter, you must also specify --dev-node");
6489 +
6490 +           netsh_ifconfig (&tt->options,
6491 +                           actual,
6492 +                           tt->local,
6493 +                           tt->adapter_netmask,
6494 +                           NI_IP_NETMASK|NI_OPTIONS);
6495 +
6496 +           break;
6497 +         }
6498 +       tt->did_ifconfig = true;
6499 +      }
6500 +
6501 +    /* IPv6 always uses "netsh" interface */
6502 +    if ( do_ipv6 )
6503 +      {
6504 +       char * saved_actual;
6505 +
6506 +       if (!strcmp (actual, "NULL"))
6507 +         msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Win32 adapter, you must also specify --dev-node");
6508 +
6509 +       /* example: netsh interface ipv6 set address MyTap 2001:608:8003::d store=active */
6510 +       argv_printf (&argv,
6511 +                   "%s%sc interface ipv6 set address %s %s store=active",
6512 +                    get_win_sys_path(),
6513 +                    NETSH_PATH_SUFFIX,
6514 +                    actual,
6515 +                    ifconfig_ipv6_local );
6516 +
6517 +       netsh_command (&argv, 4);
6518 +
6519 +       /* explicit route needed */
6520 +       /* on windows, OpenVPN does ifconfig first, open_tun later, so
6521 +        * tt->actual_name might not yet be initialized, but routing code
6522 +        * needs to know interface name - point to "actual", restore later
6523 +        */
6524 +       saved_actual = tt->actual_name;
6525 +       tt->actual_name = (char*) actual;
6526 +       add_route_connected_v6_net(tt, es);
6527 +       tt->actual_name = saved_actual;
6528 +      }
6529 +#else
6530 +      msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system.  You should ifconfig your TUN/TAP device manually or use an --up script.");
6531 +#endif
6532 +      argv_reset (&argv);
6533 +    }
6534 +  gc_free (&gc);
6535 +}
6536 +
6537 +void
6538 +clear_tuntap (struct tuntap *tuntap)
6539 +{
6540 +  CLEAR (*tuntap);
6541 +#ifdef WIN32
6542 +  tuntap->hand = NULL;
6543 +#else
6544 +  tuntap->fd = -1;
6545 +#endif
6546 +#ifdef TARGET_SOLARIS
6547 +  tuntap->ip_fd = -1;
6548 +#endif
6549 +  tuntap->ipv6 = false;
6550 +}
6551 +
6552 +static void
6553 +open_null (struct tuntap *tt)
6554 +{
6555 +  tt->actual_name = string_alloc ("null", NULL);
6556 +}
6557 +
6558 +#ifndef WIN32
6559 +static void
6560 +open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
6561 +                 bool ipv6_explicitly_supported, bool dynamic,
6562 +                 struct tuntap *tt)
6563 +{
6564 +  char tunname[256];
6565 +  char dynamic_name[256];
6566 +  bool dynamic_opened = false;
6567 +
6568 +
6569 +  if ( tt->ipv6 && ! ipv6_explicitly_supported )
6570 +    msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
6571 +
6572 +  if (tt->type == DEV_TYPE_NULL)
6573 +    {
6574 +      open_null (tt);
6575 +    }
6576 +  else
6577 +    {
6578 +      /*
6579 +       * --dev-node specified, so open an explicit device node
6580 +       */
6581 +      if (dev_node)
6582 +       {
6583 +         openvpn_snprintf (tunname, sizeof (tunname), "%s", dev_node);
6584 +       }
6585 +      else
6586 +       {
6587 +         /*
6588 +          * dynamic open is indicated by --dev specified without
6589 +          * explicit unit number.  Try opening /dev/[dev]n
6590 +          * where n = [0, 255].
6591 +          */
6592 +         if (dynamic && !has_digit((unsigned char *)dev))
6593 +           {
6594 +             int i;
6595 +             for (i = 0; i < 256; ++i)
6596 +               {
6597 +                 openvpn_snprintf (tunname, sizeof (tunname),
6598 +                                   "/dev/%s%d", dev, i);
6599 +                 openvpn_snprintf (dynamic_name, sizeof (dynamic_name),
6600 +                                   "%s%d", dev, i);
6601 +                 if ((tt->fd = open (tunname, O_RDWR)) > 0)
6602 +                   {
6603 +                     dynamic_opened = true;
6604 +                     break;
6605 +                   }
6606 +                 msg (D_READ_WRITE | M_ERRNO, "Tried opening %s (failed)", tunname);
6607 +               }
6608 +             if (!dynamic_opened)
6609 +               msg (M_FATAL, "Cannot allocate TUN/TAP dev dynamically");
6610 +           }
6611 +         /*
6612 +          * explicit unit number specified
6613 +          */
6614 +         else
6615 +           {
6616 +             openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dev);
6617 +           }
6618 +       }
6619 +
6620 +      if (!dynamic_opened)
6621 +       {
6622 +         if ((tt->fd = open (tunname, O_RDWR)) < 0)
6623 +           msg (M_ERR, "Cannot open TUN/TAP dev %s", tunname);
6624 +       }
6625 +
6626 +      set_nonblock (tt->fd);
6627 +      set_cloexec (tt->fd); /* don't pass fd to scripts */
6628 +      msg (M_INFO, "TUN/TAP device %s opened", tunname);
6629 +
6630 +      /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */
6631 +      tt->actual_name = string_alloc (dynamic_opened ? dynamic_name : dev, NULL);
6632 +    }
6633 +}
6634 +
6635 +static void
6636 +close_tun_generic (struct tuntap *tt)
6637 +{
6638 +  if (tt->fd >= 0)
6639 +    close (tt->fd);
6640 +  if (tt->actual_name)
6641 +    free (tt->actual_name);
6642 +  clear_tuntap (tt);
6643 +}
6644 +
6645 +#endif
6646 +
6647 +#if defined(TARGET_LINUX)
6648 +
6649 +#ifdef HAVE_LINUX_IF_TUN_H     /* New driver support */
6650 +
6651 +#ifndef HAVE_LINUX_SOCKIOS_H
6652 +#error header file linux/sockios.h required
6653 +#endif
6654 +
6655 +#if defined(HAVE_TUN_PI) && defined(HAVE_IPHDR) && defined(HAVE_IOVEC) && defined(ETH_P_IPV6) && defined(ETH_P_IP) && defined(HAVE_READV) && defined(HAVE_WRITEV)
6656 +#define LINUX_IPV6 1
6657 +/* #warning IPv6 ON */
6658 +#else
6659 +#define LINUX_IPV6 0
6660 +/* #warning IPv6 OFF */
6661 +#endif
6662 +
6663 +#if !PEDANTIC
6664 +
6665 +void
6666 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
6667 +{
6668 +  struct ifreq ifr;
6669 +
6670 +  /* warn if a very old linux version is used & --tun-ipv6 set
6671 +   */
6672 +#if LINUX_IPV6 == 0
6673 +  if ( tt->ipv6 )
6674 +    msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
6675 +#endif
6676 +
6677 +  /*
6678 +   * We handle --dev null specially, we do not open /dev/null for this.
6679 +   */
6680 +  if (tt->type == DEV_TYPE_NULL)
6681 +    {
6682 +      open_null (tt);
6683 +    }
6684 +  else
6685 +    {
6686 +      /*
6687 +       * Process --dev-node
6688 +       */
6689 +      const char *node = dev_node;
6690 +      if (!node)
6691 +       node = "/dev/net/tun";
6692 +
6693 +      /*
6694 +       * Open the interface
6695 +       */
6696 +      if ((tt->fd = open (node, O_RDWR)) < 0)
6697 +       {
6698 +         msg (M_WARN | M_ERRNO, "Note: Cannot open TUN/TAP dev %s", node);
6699 +         return;
6700 +       }
6701 +
6702 +      /*
6703 +       * Process --tun-ipv6
6704 +       */
6705 +      CLEAR (ifr);
6706 +      if (!tt->ipv6)
6707 +       ifr.ifr_flags = IFF_NO_PI;
6708 +
6709 +#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
6710 +      ifr.ifr_flags |= IFF_ONE_QUEUE;
6711 +#endif
6712 +
6713 +      /*
6714 +       * Figure out if tun or tap device
6715 +       */
6716 +      if (tt->type == DEV_TYPE_TUN)
6717 +       {
6718 +         ifr.ifr_flags |= IFF_TUN;
6719 +       }
6720 +      else if (tt->type == DEV_TYPE_TAP)
6721 +       {
6722 +         ifr.ifr_flags |= IFF_TAP;
6723 +       }
6724 +      else
6725 +       {
6726 +         msg (M_FATAL, "I don't recognize device %s as a tun or tap device",
6727 +              dev);
6728 +       }
6729 +
6730 +      /*
6731 +       * Set an explicit name, if --dev is not tun or tap
6732 +       */
6733 +      if (strcmp(dev, "tun") && strcmp(dev, "tap"))
6734 +       strncpynt (ifr.ifr_name, dev, IFNAMSIZ);
6735 +
6736 +      /*
6737 +       * Use special ioctl that configures tun/tap device with the parms
6738 +       * we set in ifr
6739 +       */
6740 +      if (ioctl (tt->fd, TUNSETIFF, (void *) &ifr) < 0)
6741 +       {
6742 +         msg (M_WARN | M_ERRNO, "Note: Cannot ioctl TUNSETIFF %s", dev);
6743 +         return;
6744 +       }
6745 +
6746 +      msg (M_INFO, "TUN/TAP device %s opened", ifr.ifr_name);
6747 +
6748 +      /*
6749 +       * Try making the TX send queue bigger
6750 +       */
6751 +#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
6752 +      if (tt->options.txqueuelen) {
6753 +       struct ifreq netifr;
6754 +       int ctl_fd;
6755 +
6756 +       if ((ctl_fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0)
6757 +         {
6758 +           CLEAR (netifr);
6759 +           strncpynt (netifr.ifr_name, ifr.ifr_name, IFNAMSIZ);
6760 +           netifr.ifr_qlen = tt->options.txqueuelen;
6761 +           if (ioctl (ctl_fd, SIOCSIFTXQLEN, (void *) &netifr) >= 0)
6762 +             msg (D_OSBUF, "TUN/TAP TX queue length set to %d", tt->options.txqueuelen);
6763 +           else
6764 +             msg (M_WARN | M_ERRNO, "Note: Cannot set tx queue length on %s", ifr.ifr_name);
6765 +           close (ctl_fd);
6766 +         }
6767 +       else
6768 +         {
6769 +           msg (M_WARN | M_ERRNO, "Note: Cannot open control socket on %s", ifr.ifr_name);
6770 +         }
6771 +      }
6772 +#endif
6773 +
6774 +      set_nonblock (tt->fd);
6775 +      set_cloexec (tt->fd);
6776 +      tt->actual_name = string_alloc (ifr.ifr_name, NULL);
6777 +    }
6778 +  return;
6779 +}
6780 +
6781 +#else
6782 +
6783 +void
6784 +open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
6785 +{
6786 +  ASSERT (0);
6787 +}
6788 +
6789 +#endif
6790 +
6791 +#else
6792 +
6793 +void
6794 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
6795 +{
6796 +  open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt);
6797 +}
6798 +
6799 +#endif /* HAVE_LINUX_IF_TUN_H */
6800 +
6801 +#ifdef TUNSETPERSIST
6802 +
6803 +/*
6804 + * This can be removed in future
6805 + * when all systems will use newer
6806 + * linux-headers
6807 + */
6808 +#ifndef TUNSETOWNER
6809 +#define TUNSETOWNER    _IOW('T', 204, int)
6810 +#endif
6811 +#ifndef TUNSETGROUP
6812 +#define TUNSETGROUP    _IOW('T', 206, int)
6813 +#endif
6814 +
6815 +void
6816 +tuncfg (const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
6817 +{
6818 +  struct tuntap *tt;
6819 +
6820 +  ALLOC_OBJ (tt, struct tuntap);
6821 +  clear_tuntap (tt);
6822 +  tt->type = dev_type_enum (dev, dev_type);
6823 +  tt->options = *options;
6824 +  open_tun (dev, dev_type, dev_node, tt);
6825 +  if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0)
6826 +    msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev);
6827 +  if (username != NULL)
6828 +    {
6829 +      struct user_state user_state;
6830 +
6831 +      if (!get_user (username, &user_state))
6832 +        msg (M_ERR, "Cannot get user entry for %s", username);
6833 +      else
6834 +        if (ioctl (tt->fd, TUNSETOWNER, user_state.pw->pw_uid) < 0)
6835 +          msg (M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", username, dev);
6836 +    }
6837 +  if (groupname != NULL)
6838 +    {
6839 +      struct group_state group_state;
6840 +
6841 +      if (!get_group (groupname, &group_state))
6842 +        msg (M_ERR, "Cannot get group entry for %s", groupname);
6843 +      else
6844 +        if (ioctl (tt->fd, TUNSETGROUP, group_state.gr->gr_gid) < 0)
6845 +          msg (M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", groupname, dev);
6846 +    }
6847 +  close_tun (tt);
6848 +  msg (M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF"));
6849 +}
6850 +
6851 +#endif /* TUNSETPERSIST */
6852 +
6853 +void
6854 +close_tun (struct tuntap *tt)
6855 +{
6856 +  if (tt)
6857 +    {
6858 +       if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig)
6859 +         {
6860 +           struct argv argv;
6861 +           struct gc_arena gc = gc_new ();
6862 +           argv_init (&argv);
6863 +
6864 +#ifdef CONFIG_FEATURE_IPROUTE
6865 +           if (is_tun_p2p (tt))
6866 +             {
6867 +               argv_printf (&argv,
6868 +                       "%s addr del dev %s local %s peer %s",
6869 +                       iproute_path,
6870 +                       tt->actual_name,
6871 +                       print_in_addr_t (tt->local, 0, &gc),
6872 +                       print_in_addr_t (tt->remote_netmask, 0, &gc)
6873 +                       );
6874 +             }
6875 +           else
6876 +             {
6877 +               argv_printf (&argv,
6878 +                       "%s addr del dev %s %s/%d",
6879 +                       iproute_path,
6880 +                       tt->actual_name,
6881 +                       print_in_addr_t (tt->local, 0, &gc),
6882 +                       count_netmask_bits(print_in_addr_t (tt->remote_netmask, 0, &gc))
6883 +                       );
6884 +             }
6885 +#else
6886 +           argv_printf (&argv,
6887 +                       "%s %s 0.0.0.0",
6888 +                       IFCONFIG_PATH,
6889 +                       tt->actual_name
6890 +                       );
6891 +#endif
6892 +
6893 +           argv_msg (M_INFO, &argv);
6894 +           openvpn_execve_check (&argv, NULL, 0, "Linux ip addr del failed");
6895 +
6896 +           argv_reset (&argv);
6897 +           gc_free (&gc);
6898 +         }
6899 +      close_tun_generic (tt);
6900 +      free (tt);
6901 +    }
6902 +}
6903 +
6904 +int
6905 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
6906 +{
6907 +#if LINUX_IPV6
6908 +  if (tt->ipv6)
6909 +    {
6910 +      struct tun_pi pi;
6911 +      struct iphdr *iph;
6912 +      struct iovec vect[2];
6913 +      int ret;
6914 +
6915 +      iph = (struct iphdr *)buf;
6916 +
6917 +      pi.flags = 0;
6918 +
6919 +      if(iph->version == 6)
6920 +       pi.proto = htons(ETH_P_IPV6);
6921 +      else
6922 +       pi.proto = htons(ETH_P_IP);
6923 +
6924 +      vect[0].iov_len = sizeof(pi);
6925 +      vect[0].iov_base = &pi;
6926 +      vect[1].iov_len = len;
6927 +      vect[1].iov_base = buf;
6928 +
6929 +      ret = writev(tt->fd, vect, 2);
6930 +      return(ret - sizeof(pi));
6931 +    }
6932 +  else
6933 +#endif
6934 +    return write (tt->fd, buf, len);
6935 +}
6936 +
6937 +int
6938 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
6939 +{
6940 +#if LINUX_IPV6
6941 +  if (tt->ipv6)
6942 +    {
6943 +      struct iovec vect[2];
6944 +      struct tun_pi pi;
6945 +      int ret;
6946 +
6947 +      vect[0].iov_len = sizeof(pi);
6948 +      vect[0].iov_base = &pi;
6949 +      vect[1].iov_len = len;
6950 +      vect[1].iov_base = buf;
6951 +
6952 +      ret = readv(tt->fd, vect, 2);
6953 +      return(ret - sizeof(pi));
6954 +    }
6955 +  else
6956 +#endif
6957 +    return read (tt->fd, buf, len);
6958 +}
6959 +
6960 +#elif defined(TARGET_SOLARIS)
6961 +
6962 +#ifndef TUNNEWPPA
6963 +#error I need the symbol TUNNEWPPA from net/if_tun.h
6964 +#endif
6965 +
6966 +void
6967 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
6968 +{
6969 +  int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1;
6970 +  struct lifreq ifr;
6971 +  const char *ptr;
6972 +  const char *ip_node, *arp_node;
6973 +  const char *dev_tuntap_type;
6974 +  int link_type;
6975 +  bool is_tun;
6976 +  struct strioctl  strioc_if, strioc_ppa;
6977 +
6978 +  /* improved generic TUN/TAP driver from
6979 +   * http://www.whiteboard.ne.jp/~admin2/tuntap/
6980 +   * has IPv6 support
6981 +   */
6982 +  CLEAR(ifr);
6983 +
6984 +  if (tt->type == DEV_TYPE_NULL)
6985 +    {
6986 +      open_null (tt);
6987 +      return;
6988 +    }
6989 +
6990 +  if (tt->type == DEV_TYPE_TUN)
6991 +    {
6992 +      ip_node = "/dev/udp";
6993 +      if (!dev_node)
6994 +       dev_node = "/dev/tun";
6995 +      dev_tuntap_type = "tun";
6996 +      link_type = I_PLINK;
6997 +      is_tun = true;
6998 +    }
6999 +  else if (tt->type == DEV_TYPE_TAP)
7000 +    {
7001 +      ip_node = "/dev/udp";
7002 +      if (!dev_node)
7003 +       dev_node = "/dev/tap";
7004 +      arp_node = dev_node;
7005 +      dev_tuntap_type = "tap";
7006 +      link_type = I_PLINK; /* was: I_LINK */
7007 +      is_tun = false;
7008 +    }
7009 +  else
7010 +    {
7011 +      msg (M_FATAL, "I don't recognize device %s as a tun or tap device",
7012 +          dev);
7013 +    }
7014 +  
7015 +  /* get unit number */
7016 +  if (*dev)
7017 +    {
7018 +      ptr = dev;
7019 +      while (*ptr && !isdigit ((int) *ptr))
7020 +       ptr++;
7021 +      ppa = atoi (ptr);
7022 +    }
7023 +
7024 +  if ((tt->ip_fd = open (ip_node, O_RDWR, 0)) < 0)
7025 +    msg (M_ERR, "Can't open %s", ip_node);
7026 +
7027 +  if ((tt->fd = open (dev_node, O_RDWR, 0)) < 0)
7028 +    msg (M_ERR, "Can't open %s", dev_node);
7029 +
7030 +  /* Assign a new PPA and get its unit number. */
7031 +  strioc_ppa.ic_cmd = TUNNEWPPA;
7032 +  strioc_ppa.ic_timout = 0;
7033 +  strioc_ppa.ic_len = sizeof(ppa);
7034 +  strioc_ppa.ic_dp = (char *)&ppa;
7035 +  if ((ppa = ioctl (tt->fd, I_STR, &strioc_ppa)) < 0)
7036 +    msg (M_ERR, "Can't assign new interface");
7037 +
7038 +  if ((if_fd = open (dev_node, O_RDWR, 0)) < 0)
7039 +    msg (M_ERR, "Can't open %s (2)", dev_node);
7040 +
7041 +  if (ioctl (if_fd, I_PUSH, "ip") < 0)
7042 +    msg (M_ERR, "Can't push IP module");
7043 +
7044 +  if (tt->type == DEV_TYPE_TUN)
7045 +    {
7046 +  /* Assign ppa according to the unit number returned by tun device */
7047 +  if (ioctl (if_fd, IF_UNITSEL, (char *) &ppa) < 0)
7048 +    msg (M_ERR, "Can't set PPA %d", ppa);
7049 +    }
7050 +
7051 +  tt->actual_name = (char *) malloc (32);
7052 +  check_malloc_return (tt->actual_name);
7053 +
7054 +  openvpn_snprintf (tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa);
7055 +
7056 +  if (tt->type == DEV_TYPE_TAP)
7057 +    {
7058 +          if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
7059 +            msg (M_ERR, "Can't get flags\n");
7060 +          strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
7061 +          ifr.lifr_ppa = ppa;
7062 +          /* Assign ppa according to the unit number returned by tun device */
7063 +          if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
7064 +            msg (M_ERR, "Can't set PPA %d", ppa);
7065 +          if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
7066 +            msg (M_ERR, "Can't get flags\n");
7067 +          /* Push arp module to if_fd */
7068 +          if (ioctl (if_fd, I_PUSH, "arp") < 0)
7069 +            msg (M_ERR, "Can't push ARP module");
7070 +
7071 +          /* Pop any modules on the stream */
7072 +          while (true)
7073 +            {
7074 +                 if (ioctl (tt->ip_fd, I_POP, NULL) < 0)
7075 +                     break;
7076 +            }
7077 +          /* Push arp module to ip_fd */
7078 +          if (ioctl (tt->ip_fd, I_PUSH, "arp") < 0)
7079 +            msg (M_ERR, "Can't push ARP module\n");
7080 +
7081 +          /* Open arp_fd */
7082 +          if ((arp_fd = open (arp_node, O_RDWR, 0)) < 0)
7083 +            msg (M_ERR, "Can't open %s\n", arp_node);
7084 +          /* Push arp module to arp_fd */
7085 +          if (ioctl (arp_fd, I_PUSH, "arp") < 0)
7086 +            msg (M_ERR, "Can't push ARP module\n");
7087 +
7088 +          /* Set ifname to arp */
7089 +          strioc_if.ic_cmd = SIOCSLIFNAME;
7090 +          strioc_if.ic_timout = 0;
7091 +          strioc_if.ic_len = sizeof(ifr);
7092 +          strioc_if.ic_dp = (char *)&ifr;
7093 +          if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
7094 +              msg (M_ERR, "Can't set ifname to arp\n");
7095 +          }
7096 +   }
7097 +
7098 +  if ((ip_muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0)
7099 +    msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type);
7100 +
7101 +  if (tt->type == DEV_TYPE_TAP) {
7102 +          if ((arp_muxid = ioctl (tt->ip_fd, link_type, arp_fd)) < 0)
7103 +            msg (M_ERR, "Can't link %s device to ARP", dev_tuntap_type);
7104 +          close (arp_fd);
7105 +  }
7106 +
7107 +  CLEAR (ifr);
7108 +  strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
7109 +  ifr.lifr_ip_muxid  = ip_muxid;
7110 +  if (tt->type == DEV_TYPE_TAP) {
7111 +          ifr.lifr_arp_muxid = arp_muxid;
7112 +  }
7113 +
7114 +  if (ioctl (tt->ip_fd, SIOCSLIFMUXID, &ifr) < 0)
7115 +    {
7116 +      if (tt->type == DEV_TYPE_TAP)
7117 +        {
7118 +              ioctl (tt->ip_fd, I_PUNLINK , arp_muxid);
7119 +        }
7120 +      ioctl (tt->ip_fd, I_PUNLINK, ip_muxid);
7121 +      msg (M_ERR, "Can't set multiplexor id");
7122 +    }
7123 +
7124 +  set_nonblock (tt->fd);
7125 +  set_cloexec (tt->fd);
7126 +  set_cloexec (tt->ip_fd);
7127 +
7128 +  msg (M_INFO, "TUN/TAP device %s opened", tt->actual_name);
7129 +}
7130 +
7131 +static void
7132 +solaris_close_tun (struct tuntap *tt)
7133 +{
7134 +  if (tt)
7135 +    {
7136 +      /* IPv6 interfaces need to be 'manually' de-configured */
7137 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
7138 +       {
7139 +         struct argv argv;
7140 +         argv_init (&argv);
7141 +         argv_printf( &argv, "%s %s inet6 unplumb",
7142 +                      IFCONFIG_PATH, tt->actual_name );
7143 +         argv_msg (M_INFO, &argv);
7144 +         openvpn_execve_check (&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed");
7145 +         argv_reset (&argv);
7146 +       }
7147 +
7148 +      if (tt->ip_fd >= 0)
7149 +       {
7150 +          struct lifreq ifr;
7151 +         CLEAR (ifr);
7152 +          strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
7153 +
7154 +          if (ioctl (tt->ip_fd, SIOCGLIFFLAGS, &ifr) < 0)
7155 +           msg (M_WARN | M_ERRNO, "Can't get iface flags");
7156 +
7157 +          if (ioctl (tt->ip_fd, SIOCGLIFMUXID, &ifr) < 0)
7158 +           msg (M_WARN | M_ERRNO, "Can't get multiplexor id");
7159 +
7160 +          if (tt->type == DEV_TYPE_TAP)
7161 +            {
7162 +                  if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_arp_muxid) < 0)
7163 +                    msg (M_WARN | M_ERRNO, "Can't unlink interface(arp)");
7164 +            }
7165 +
7166 +          if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0)
7167 +            msg (M_WARN | M_ERRNO, "Can't unlink interface(ip)");
7168 +
7169 +         close (tt->ip_fd);
7170 +         tt->ip_fd = -1;
7171 +       }
7172 +
7173 +      if (tt->fd >= 0)
7174 +       {
7175 +         close (tt->fd);
7176 +         tt->fd = -1;
7177 +       }
7178 +    }
7179 +}
7180 +
7181 +/*
7182 + * Close TUN device. 
7183 + */
7184 +void
7185 +close_tun (struct tuntap *tt)
7186 +{
7187 +  if (tt)
7188 +    {
7189 +      solaris_close_tun (tt);
7190 +
7191 +      if (tt->actual_name)
7192 +       free (tt->actual_name);
7193 +      
7194 +      clear_tuntap (tt);
7195 +      free (tt);
7196 +    }
7197 +}
7198 +
7199 +static void
7200 +solaris_error_close (struct tuntap *tt, const struct env_set *es, 
7201 +                     const char *actual, bool unplumb_inet6 )
7202 +{
7203 +  struct argv argv;
7204 +  argv_init (&argv);
7205 +
7206 +  if (unplumb_inet6)
7207 +    {
7208 +      argv_printf( &argv, "%s %s inet6 unplumb",
7209 +                  IFCONFIG_PATH, actual );
7210 +      argv_msg (M_INFO, &argv);
7211 +      openvpn_execve_check (&argv, es, 0, "Solaris ifconfig inet6 unplumb failed");
7212 +    }
7213 +
7214 +  argv_printf (&argv,
7215 +                   "%s %s unplumb",
7216 +                   IFCONFIG_PATH,
7217 +                   actual);
7218 +
7219 +  argv_msg (M_INFO, &argv);
7220 +  openvpn_execve_check (&argv, es, 0, "Solaris ifconfig unplumb failed");
7221 +  close_tun (tt);
7222 +  msg (M_FATAL, "Solaris ifconfig failed");
7223 +  argv_reset (&argv);
7224 +}
7225 +
7226 +int
7227 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
7228 +{
7229 +  struct strbuf sbuf;
7230 +  sbuf.len = len;
7231 +  sbuf.buf = (char *)buf;
7232 +  return putmsg (tt->fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1;
7233 +}
7234 +
7235 +int
7236 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
7237 +{
7238 +  struct strbuf sbuf;
7239 +  int f = 0;
7240 +
7241 +  sbuf.maxlen = len;
7242 +  sbuf.buf = (char *)buf;
7243 +  return getmsg (tt->fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
7244 +}
7245 +
7246 +#elif defined(TARGET_OPENBSD)
7247 +
7248 +#if !defined(HAVE_READV) || !defined(HAVE_WRITEV)
7249 +#error openbsd build requires readv & writev library functions
7250 +#endif
7251 +
7252 +/*
7253 + * OpenBSD has a slightly incompatible TUN device from
7254 + * the rest of the world, in that it prepends a
7255 + * uint32 to the beginning of the IP header
7256 + * to designate the protocol (why not just
7257 + * look at the version field in the IP header to
7258 + * determine v4 or v6?).
7259 + *
7260 + * We strip off this field on reads and
7261 + * put it back on writes.
7262 + *
7263 + * I have not tested TAP devices on OpenBSD,
7264 + * but I have conditionalized the special
7265 + * TUN handling code described above to
7266 + * go away for TAP devices.
7267 + */
7268 +
7269 +void
7270 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
7271 +{
7272 +  open_tun_generic (dev, dev_type, dev_node, true, true, tt);
7273 +
7274 +  /* Enable multicast on the interface */
7275 +  if (tt->fd >= 0)
7276 +    {
7277 +      struct tuninfo info;
7278 +
7279 +      if (ioctl (tt->fd, TUNGIFINFO, &info) < 0) {
7280 +       msg (M_WARN | M_ERRNO, "Can't get interface info: %s",
7281 +         strerror(errno));
7282 +      }
7283 +
7284 +      info.flags |= IFF_MULTICAST;
7285 +
7286 +      if (ioctl (tt->fd, TUNSIFINFO, &info) < 0) {
7287 +       msg (M_WARN | M_ERRNO, "Can't set interface info: %s",
7288 +         strerror(errno));
7289 +      }
7290 +    }
7291 +}
7292 +
7293 +/* the current way OpenVPN handles tun devices on OpenBSD leads to
7294 + * lingering tunX interfaces after close -> for a full cleanup, they
7295 + * need to be explicitely destroyed
7296 + */
7297 +
7298 +void
7299 +close_tun (struct tuntap* tt)
7300 +{
7301 +  if (tt)
7302 +    {
7303 +      struct gc_arena gc = gc_new ();
7304 +      struct argv argv;
7305 +
7306 +      /* setup command, close tun dev (clears tt->actual_name!), run command
7307 +       */
7308 +
7309 +      argv_init (&argv);
7310 +      argv_printf (&argv, "%s %s destroy",
7311 +                          IFCONFIG_PATH, tt->actual_name);
7312 +
7313 +      close_tun_generic (tt);
7314 +
7315 +      argv_msg (M_INFO, &argv);
7316 +      openvpn_execve_check (&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)");
7317 +
7318 +      free (tt);
7319 +    }
7320 +}
7321 +
7322 +static inline int
7323 +openbsd_modify_read_write_return (int len)
7324 +{
7325 + if (len > 0)
7326 +    return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
7327 +  else
7328 +    return len;
7329 +}
7330 +
7331 +int
7332 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
7333 +{
7334 +  if (tt->type == DEV_TYPE_TUN)
7335 +    {
7336 +      u_int32_t type;
7337 +      struct iovec iv[2];
7338 +      struct ip *iph;
7339 +
7340 +      iph = (struct ip *) buf;
7341 +
7342 +      if (tt->ipv6 && iph->ip_v == 6)
7343 +       type = htonl (AF_INET6);
7344 +      else 
7345 +       type = htonl (AF_INET);
7346 +
7347 +      iv[0].iov_base = &type;
7348 +      iv[0].iov_len = sizeof (type);
7349 +      iv[1].iov_base = buf;
7350 +      iv[1].iov_len = len;
7351 +
7352 +      return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
7353 +    }
7354 +  else
7355 +    return write (tt->fd, buf, len);
7356 +}
7357 +
7358 +int
7359 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
7360 +{
7361 +  if (tt->type == DEV_TYPE_TUN)
7362 +    {
7363 +      u_int32_t type;
7364 +      struct iovec iv[2];
7365 +
7366 +      iv[0].iov_base = &type;
7367 +      iv[0].iov_len = sizeof (type);
7368 +      iv[1].iov_base = buf;
7369 +      iv[1].iov_len = len;
7370 +
7371 +      return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
7372 +    }
7373 +  else
7374 +    return read (tt->fd, buf, len);
7375 +}
7376 +
7377 +#elif defined(TARGET_NETBSD)
7378 +
7379 +/*
7380 + * NetBSD before 4.0 does not support IPv6 on tun out of the box,
7381 + * but there exists a patch (sys/net/if_tun.c, 1.79->1.80, see PR 32944).
7382 + *
7383 + * NetBSD 4.0 and up do, but we need to put the tun interface into
7384 + * "multi_af" mode, which will prepend the address family to all packets
7385 + * (same as OpenBSD and FreeBSD).  If this is not enabled, the kernel
7386 + * silently drops all IPv6 packets on output and gets confused on input.
7387 + *
7388 + * On earlier versions, multi_af is not available at all, so we have
7389 + * two different NetBSD code variants here :-(
7390 + *
7391 + */
7392 +
7393 +void
7394 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
7395 +{
7396 +#ifdef NETBSD_MULTI_AF
7397 +    open_tun_generic (dev, dev_type, dev_node, true, true, tt);
7398 +#else
7399 +    open_tun_generic (dev, dev_type, dev_node, false, true, tt);
7400 +#endif
7401 +
7402 +    if (tt->fd >= 0)
7403 +      {
7404 +        int i = IFF_POINTOPOINT|IFF_MULTICAST;
7405 +        ioctl (tt->fd, TUNSIFMODE, &i);  /* multicast on */
7406 +        i = 0;
7407 +        ioctl (tt->fd, TUNSLMODE, &i);   /* link layer mode off */
7408 +
7409 +#ifdef NETBSD_MULTI_AF
7410 +        i = 1;
7411 +        if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0)        /* multi-af mode on */
7412 +         {
7413 +           msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
7414 +         }
7415 +#endif
7416 +      }
7417 +}
7418 +
7419 +void
7420 +close_tun (struct tuntap *tt)
7421 +{
7422 +  /* TODO: we really should cleanup non-persistant tunX with 
7423 +   * "ifconfig tunX destroy" here...
7424 +   */
7425 +  if (tt)
7426 +    {
7427 +      close_tun_generic (tt);
7428 +      free (tt);
7429 +    }
7430 +}
7431 +
7432 +#ifdef NETBSD_MULTI_AF
7433 +
7434 +static inline int
7435 +netbsd_modify_read_write_return (int len)
7436 +{
7437 +  if (len > 0)
7438 +    return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
7439 +  else
7440 +    return len;
7441 +}
7442 +
7443 +int
7444 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
7445 +{
7446 +  if (tt->type == DEV_TYPE_TUN)
7447 +    {
7448 +      u_int32_t type;
7449 +      struct iovec iv[2];
7450 +      struct openvpn_iphdr *iph;
7451 +
7452 +      iph = (struct openvpn_iphdr *) buf;
7453 +
7454 +      if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6)
7455 +        type = htonl (AF_INET6);
7456 +      else 
7457 +        type = htonl (AF_INET);
7458 +
7459 +      iv[0].iov_base = (char *)&type;
7460 +      iv[0].iov_len = sizeof (type);
7461 +      iv[1].iov_base = buf;
7462 +      iv[1].iov_len = len;
7463 +
7464 +      return netbsd_modify_read_write_return (writev (tt->fd, iv, 2));
7465 +    }
7466 +  else
7467 +    return write (tt->fd, buf, len);
7468 +}
7469 +
7470 +int
7471 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
7472 +{
7473 +  if (tt->type == DEV_TYPE_TUN)
7474 +    {
7475 +      u_int32_t type;
7476 +      struct iovec iv[2];
7477 +
7478 +      iv[0].iov_base = (char *)&type;
7479 +      iv[0].iov_len = sizeof (type);
7480 +      iv[1].iov_base = buf;
7481 +      iv[1].iov_len = len;
7482 +
7483 +      return netbsd_modify_read_write_return (readv (tt->fd, iv, 2));
7484 +    }
7485 +  else
7486 +    return read (tt->fd, buf, len);
7487 +}
7488 +
7489 +#else  /* not NETBSD_MULTI_AF -> older code, IPv4 only */
7490 +
7491 +int
7492 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
7493 +{
7494 +    return write (tt->fd, buf, len);
7495 +}
7496 +
7497 +int
7498 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
7499 +{
7500 +    return read (tt->fd, buf, len);
7501 +}
7502 +#endif /* NETBSD_MULTI_AF */
7503 +
7504 +#elif defined(TARGET_FREEBSD)
7505 +
7506 +static inline int
7507 +freebsd_modify_read_write_return (int len)
7508 +{
7509 +  if (len > 0)
7510 +    return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
7511 +  else
7512 +    return len;
7513 +}
7514 +
7515 +void
7516 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
7517 +{
7518 +  open_tun_generic (dev, dev_type, dev_node, true, true, tt);
7519 +
7520 +  if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN)
7521 +    {
7522 +      int i = 0;
7523 +
7524 +      i = tt->topology == TOP_SUBNET ? IFF_BROADCAST : IFF_POINTOPOINT;
7525 +      i |= IFF_MULTICAST;
7526 +      if (ioctl (tt->fd, TUNSIFMODE, &i) < 0) {
7527 +       msg (M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno));
7528 +      }
7529 +      i = 1;
7530 +      if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) {
7531 +       msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
7532 +      }
7533 +    }
7534 +}
7535 +
7536 +void
7537 +close_tun (struct tuntap *tt)
7538 +{
7539 +  if (tt)
7540 +    {
7541 +      close_tun_generic (tt);
7542 +      free (tt);
7543 +    }
7544 +}
7545 +
7546 +int
7547 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
7548 +{
7549 +  if (tt->type == DEV_TYPE_TUN)
7550 +    {
7551 +      u_int32_t type;
7552 +      struct iovec iv[2];
7553 +      struct ip *iph;
7554 +
7555 +      iph = (struct ip *) buf;
7556 +
7557 +      if (tt->ipv6 && iph->ip_v == 6)
7558 +        type = htonl (AF_INET6);
7559 +      else 
7560 +        type = htonl (AF_INET);
7561 +
7562 +      iv[0].iov_base = (char *)&type;
7563 +      iv[0].iov_len = sizeof (type);
7564 +      iv[1].iov_base = buf;
7565 +      iv[1].iov_len = len;
7566 +
7567 +      return freebsd_modify_read_write_return (writev (tt->fd, iv, 2));
7568 +    }
7569 +  else
7570 +    return write (tt->fd, buf, len);
7571 +}
7572 +
7573 +int
7574 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
7575 +{
7576 +  if (tt->type == DEV_TYPE_TUN)
7577 +    {
7578 +      u_int32_t type;
7579 +      struct iovec iv[2];
7580 +
7581 +      iv[0].iov_base = (char *)&type;
7582 +      iv[0].iov_len = sizeof (type);
7583 +      iv[1].iov_base = buf;
7584 +      iv[1].iov_len = len;
7585 +
7586 +      return freebsd_modify_read_write_return (readv (tt->fd, iv, 2));
7587 +    }
7588 +  else
7589 +    return read (tt->fd, buf, len);
7590 +}
7591 +
7592 +#elif defined(TARGET_DRAGONFLY)
7593 +
7594 +static inline int
7595 +dragonfly_modify_read_write_return (int len)
7596 +{
7597 +  if (len > 0)
7598 +    return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
7599 +  else
7600 +    return len;
7601 +}
7602 +
7603 +void
7604 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
7605 +{
7606 +  open_tun_generic (dev, dev_type, dev_node, true, true, tt);
7607 +
7608 +  if (tt->fd >= 0)
7609 +    {
7610 +      int i = 0;
7611 +
7612 +      /* Disable extended modes */
7613 +      ioctl (tt->fd, TUNSLMODE, &i);
7614 +      i = 1;
7615 +      ioctl (tt->fd, TUNSIFHEAD, &i);
7616 +    }
7617 +}
7618 +
7619 +void
7620 +close_tun (struct tuntap *tt)
7621 +{
7622 +  if (tt)
7623 +    {
7624 +      close_tun_generic (tt);
7625 +      free (tt);
7626 +    }
7627 +}
7628 +
7629 +int
7630 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
7631 +{
7632 +  if (tt->type == DEV_TYPE_TUN)
7633 +    {
7634 +      u_int32_t type;
7635 +      struct iovec iv[2];
7636 +      struct ip *iph;
7637 +
7638 +      iph = (struct ip *) buf;
7639 +
7640 +      if (tt->ipv6 && iph->ip_v == 6)
7641 +        type = htonl (AF_INET6);
7642 +      else 
7643 +        type = htonl (AF_INET);
7644 +
7645 +      iv[0].iov_base = (char *)&type;
7646 +      iv[0].iov_len = sizeof (type);
7647 +      iv[1].iov_base = buf;
7648 +      iv[1].iov_len = len;
7649 +
7650 +      return dragonfly_modify_read_write_return (writev (tt->fd, iv, 2));
7651 +    }
7652 +  else
7653 +    return write (tt->fd, buf, len);
7654 +}
7655 +
7656 +int
7657 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
7658 +{
7659 +  if (tt->type == DEV_TYPE_TUN)
7660 +    {
7661 +      u_int32_t type;
7662 +      struct iovec iv[2];
7663 +
7664 +      iv[0].iov_base = (char *)&type;
7665 +      iv[0].iov_len = sizeof (type);
7666 +      iv[1].iov_base = buf;
7667 +      iv[1].iov_len = len;
7668 +
7669 +      return dragonfly_modify_read_write_return (readv (tt->fd, iv, 2));
7670 +    }
7671 +  else
7672 +    return read (tt->fd, buf, len);
7673 +}
7674 +
7675 +#elif defined(TARGET_DARWIN)
7676 +
7677 +/* Darwin (MacOS X) is mostly "just use the generic stuff", but there
7678 + * is always one caveat...:
7679 + *
7680 + * If IPv6 is configured, and the tun device is closed, the IPv6 address
7681 + * configured to the tun interface changes to a lingering /128 route
7682 + * pointing to lo0.  Need to unconfigure...  (observed on 10.5)
7683 + */
7684 +
7685 +void
7686 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
7687 +{
7688 +  open_tun_generic (dev, dev_type, dev_node, false, true, tt);
7689 +}
7690 +
7691 +void
7692 +close_tun (struct tuntap* tt)
7693 +{
7694 +  if (tt)
7695 +    {
7696 +      struct gc_arena gc = gc_new ();
7697 +      struct argv argv;
7698 +      argv_init (&argv);
7699 +
7700 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
7701 +       {
7702 +         const char * ifconfig_ipv6_local =
7703 +                               print_in6_addr (tt->local_ipv6, 0, &gc);
7704 +
7705 +          argv_printf (&argv, "%s delete -inet6 %s",
7706 +                              ROUTE_PATH, ifconfig_ipv6_local );
7707 +         argv_msg (M_INFO, &argv);
7708 +         openvpn_execve_check (&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)");
7709 +       }
7710 +
7711 +      close_tun_generic (tt);
7712 +      free (tt);
7713 +      argv_reset (&argv);
7714 +      gc_free (&gc);
7715 +    }
7716 +}
7717 +
7718 +int
7719 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
7720 +{
7721 +  return write (tt->fd, buf, len);
7722 +}
7723 +
7724 +int
7725 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
7726 +{
7727 +  return read (tt->fd, buf, len);
7728 +}
7729 +
7730 +#elif defined(WIN32)
7731 +
7732 +int
7733 +tun_read_queue (struct tuntap *tt, int maxsize)
7734 +{
7735 +  if (tt->reads.iostate == IOSTATE_INITIAL)
7736 +    {
7737 +      DWORD len;
7738 +      BOOL status;
7739 +      int err;
7740 +
7741 +      /* reset buf to its initial state */
7742 +      tt->reads.buf = tt->reads.buf_init;
7743 +
7744 +      len = maxsize ? maxsize : BLEN (&tt->reads.buf);
7745 +      ASSERT (len <= BLEN (&tt->reads.buf));
7746 +
7747 +      /* the overlapped read will signal this event on I/O completion */
7748 +      ASSERT (ResetEvent (tt->reads.overlapped.hEvent));
7749 +
7750 +      status = ReadFile(
7751 +                     tt->hand,
7752 +                     BPTR (&tt->reads.buf),
7753 +                     len,
7754 +                     &tt->reads.size,
7755 +                     &tt->reads.overlapped
7756 +                     );
7757 +
7758 +      if (status) /* operation completed immediately? */
7759 +       {
7760 +         /* since we got an immediate return, we must signal the event object ourselves */
7761 +         ASSERT (SetEvent (tt->reads.overlapped.hEvent));
7762 +
7763 +         tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
7764 +         tt->reads.status = 0;
7765 +
7766 +         dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read immediate return [%d,%d]",
7767 +              (int) len,
7768 +              (int) tt->reads.size);          
7769 +       }
7770 +      else
7771 +       {
7772 +         err = GetLastError (); 
7773 +         if (err == ERROR_IO_PENDING) /* operation queued? */
7774 +           {
7775 +             tt->reads.iostate = IOSTATE_QUEUED;
7776 +             tt->reads.status = err;
7777 +             dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read queued [%d]",
7778 +                  (int) len);
7779 +           }
7780 +         else /* error occurred */
7781 +           {
7782 +             struct gc_arena gc = gc_new ();
7783 +             ASSERT (SetEvent (tt->reads.overlapped.hEvent));
7784 +             tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
7785 +             tt->reads.status = err;
7786 +             dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read error [%d] : %s",
7787 +                  (int) len,
7788 +                  strerror_win32 (status, &gc));
7789 +             gc_free (&gc);
7790 +           }
7791 +       }
7792 +    }
7793 +  return tt->reads.iostate;
7794 +}
7795 +
7796 +int
7797 +tun_write_queue (struct tuntap *tt, struct buffer *buf)
7798 +{
7799 +  if (tt->writes.iostate == IOSTATE_INITIAL)
7800 +    {
7801 +      BOOL status;
7802 +      int err;
7803
7804 +      /* make a private copy of buf */
7805 +      tt->writes.buf = tt->writes.buf_init;
7806 +      tt->writes.buf.len = 0;
7807 +      ASSERT (buf_copy (&tt->writes.buf, buf));
7808 +
7809 +      /* the overlapped write will signal this event on I/O completion */
7810 +      ASSERT (ResetEvent (tt->writes.overlapped.hEvent));
7811 +
7812 +      status = WriteFile(
7813 +                       tt->hand,
7814 +                       BPTR (&tt->writes.buf),
7815 +                       BLEN (&tt->writes.buf),
7816 +                       &tt->writes.size,
7817 +                       &tt->writes.overlapped
7818 +                       );
7819 +
7820 +      if (status) /* operation completed immediately? */
7821 +       {
7822 +         tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
7823 +
7824 +         /* since we got an immediate return, we must signal the event object ourselves */
7825 +         ASSERT (SetEvent (tt->writes.overlapped.hEvent));
7826 +
7827 +         tt->writes.status = 0;
7828 +
7829 +         dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write immediate return [%d,%d]",
7830 +              BLEN (&tt->writes.buf),
7831 +              (int) tt->writes.size);         
7832 +       }
7833 +      else
7834 +       {
7835 +         err = GetLastError (); 
7836 +         if (err == ERROR_IO_PENDING) /* operation queued? */
7837 +           {
7838 +             tt->writes.iostate = IOSTATE_QUEUED;
7839 +             tt->writes.status = err;
7840 +             dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write queued [%d]",
7841 +                  BLEN (&tt->writes.buf));
7842 +           }
7843 +         else /* error occurred */
7844 +           {
7845 +             struct gc_arena gc = gc_new ();
7846 +             ASSERT (SetEvent (tt->writes.overlapped.hEvent));
7847 +             tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
7848 +             tt->writes.status = err;
7849 +             dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write error [%d] : %s",
7850 +                  BLEN (&tt->writes.buf),
7851 +                  strerror_win32 (err, &gc));
7852 +             gc_free (&gc);
7853 +           }
7854 +       }
7855 +    }
7856 +  return tt->writes.iostate;
7857 +}
7858 +
7859 +int
7860 +tun_finalize (
7861 +             HANDLE h,
7862 +             struct overlapped_io *io,
7863 +             struct buffer *buf)
7864 +{
7865 +  int ret = -1;
7866 +  BOOL status;
7867 +
7868 +  switch (io->iostate)
7869 +    {
7870 +    case IOSTATE_QUEUED:
7871 +      status = GetOverlappedResult(
7872 +                                  h,
7873 +                                  &io->overlapped,
7874 +                                  &io->size,
7875 +                                  FALSE
7876 +                                  );
7877 +      if (status)
7878 +       {
7879 +         /* successful return for a queued operation */
7880 +         if (buf)
7881 +           *buf = io->buf;
7882 +         ret = io->size;
7883 +         io->iostate = IOSTATE_INITIAL;
7884 +         ASSERT (ResetEvent (io->overlapped.hEvent));
7885 +         dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion success [%d]", ret);
7886 +       }
7887 +      else
7888 +       {
7889 +         /* error during a queued operation */
7890 +         ret = -1;
7891 +         if (GetLastError() != ERROR_IO_INCOMPLETE)
7892 +           {
7893 +             /* if no error (i.e. just not finished yet),
7894 +                then DON'T execute this code */
7895 +             io->iostate = IOSTATE_INITIAL;
7896 +             ASSERT (ResetEvent (io->overlapped.hEvent));
7897 +             msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion error");
7898 +           }
7899 +       }
7900 +      break;
7901 +
7902 +    case IOSTATE_IMMEDIATE_RETURN:
7903 +      io->iostate = IOSTATE_INITIAL;
7904 +      ASSERT (ResetEvent (io->overlapped.hEvent));
7905 +      if (io->status)
7906 +       {
7907 +         /* error return for a non-queued operation */
7908 +         SetLastError (io->status);
7909 +         ret = -1;
7910 +         msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion non-queued error");
7911 +       }
7912 +      else
7913 +       {
7914 +         /* successful return for a non-queued operation */
7915 +         if (buf)
7916 +           *buf = io->buf;
7917 +         ret = io->size;
7918 +         dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion non-queued success [%d]", ret);
7919 +       }
7920 +      break;
7921 +
7922 +    case IOSTATE_INITIAL: /* were we called without proper queueing? */
7923 +      SetLastError (ERROR_INVALID_FUNCTION);
7924 +      ret = -1;
7925 +      dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion BAD STATE");
7926 +      break;
7927 +
7928 +    default:
7929 +      ASSERT (0);
7930 +    }
7931 +
7932 +  if (buf)
7933 +    buf->len = ret;
7934 +  return ret;
7935 +}
7936 +
7937 +const struct tap_reg *
7938 +get_tap_reg (struct gc_arena *gc)
7939 +{
7940 +  HKEY adapter_key;
7941 +  LONG status;
7942 +  DWORD len;
7943 +  struct tap_reg *first = NULL;
7944 +  struct tap_reg *last = NULL;
7945 +  int i = 0;
7946 +
7947 +  status = RegOpenKeyEx(
7948 +                       HKEY_LOCAL_MACHINE,
7949 +                       ADAPTER_KEY,
7950 +                       0,
7951 +                       KEY_READ,
7952 +                       &adapter_key);
7953 +
7954 +  if (status != ERROR_SUCCESS)
7955 +    msg (M_FATAL, "Error opening registry key: %s", ADAPTER_KEY);
7956 +
7957 +  while (true)
7958 +    {
7959 +      char enum_name[256];
7960 +      char unit_string[256];
7961 +      HKEY unit_key;
7962 +      char component_id_string[] = "ComponentId";
7963 +      char component_id[256];
7964 +      char net_cfg_instance_id_string[] = "NetCfgInstanceId";
7965 +      char net_cfg_instance_id[256];
7966 +      DWORD data_type;
7967 +
7968 +      len = sizeof (enum_name);
7969 +      status = RegEnumKeyEx(
7970 +                           adapter_key,
7971 +                           i,
7972 +                           enum_name,
7973 +                           &len,
7974 +                           NULL,
7975 +                           NULL,
7976 +                           NULL,
7977 +                           NULL);
7978 +      if (status == ERROR_NO_MORE_ITEMS)
7979 +       break;
7980 +      else if (status != ERROR_SUCCESS)
7981 +       msg (M_FATAL, "Error enumerating registry subkeys of key: %s",
7982 +            ADAPTER_KEY);
7983 +
7984 +      openvpn_snprintf (unit_string, sizeof(unit_string), "%s\\%s",
7985 +                       ADAPTER_KEY, enum_name);
7986 +
7987 +      status = RegOpenKeyEx(
7988 +                           HKEY_LOCAL_MACHINE,
7989 +                           unit_string,
7990 +                           0,
7991 +                           KEY_READ,
7992 +                           &unit_key);
7993 +
7994 +      if (status != ERROR_SUCCESS)
7995 +       dmsg (D_REGISTRY, "Error opening registry key: %s", unit_string);
7996 +      else
7997 +       {
7998 +         len = sizeof (component_id);
7999 +         status = RegQueryValueEx(
8000 +                                  unit_key,
8001 +                                  component_id_string,
8002 +                                  NULL,
8003 +                                  &data_type,
8004 +                                  component_id,
8005 +                                  &len);
8006 +
8007 +         if (status != ERROR_SUCCESS || data_type != REG_SZ)
8008 +           dmsg (D_REGISTRY, "Error opening registry key: %s\\%s",
8009 +                unit_string, component_id_string);
8010 +         else
8011 +           {         
8012 +             len = sizeof (net_cfg_instance_id);
8013 +             status = RegQueryValueEx(
8014 +                                      unit_key,
8015 +                                      net_cfg_instance_id_string,
8016 +                                      NULL,
8017 +                                      &data_type,
8018 +                                      net_cfg_instance_id,
8019 +                                      &len);
8020 +
8021 +             if (status == ERROR_SUCCESS && data_type == REG_SZ)
8022 +               {
8023 +                 if (!strcmp (component_id, TAP_COMPONENT_ID))
8024 +                   {
8025 +                     struct tap_reg *reg;
8026 +                     ALLOC_OBJ_CLEAR_GC (reg, struct tap_reg, gc);
8027 +                     reg->guid = string_alloc (net_cfg_instance_id, gc);
8028 +                     
8029 +                     /* link into return list */
8030 +                     if (!first)
8031 +                       first = reg;
8032 +                     if (last)
8033 +                       last->next = reg;
8034 +                     last = reg;
8035 +                   }
8036 +               }
8037 +           }
8038 +         RegCloseKey (unit_key);
8039 +       }
8040 +      ++i;
8041 +    }
8042 +
8043 +  RegCloseKey (adapter_key);
8044 +  return first;
8045 +}
8046 +
8047 +const struct panel_reg *
8048 +get_panel_reg (struct gc_arena *gc)
8049 +{
8050 +  LONG status;
8051 +  HKEY network_connections_key;
8052 +  DWORD len;
8053 +  struct panel_reg *first = NULL;
8054 +  struct panel_reg *last = NULL;
8055 +  int i = 0;
8056 +
8057 +  status = RegOpenKeyEx(
8058 +                       HKEY_LOCAL_MACHINE,
8059 +                       NETWORK_CONNECTIONS_KEY,
8060 +                       0,
8061 +                       KEY_READ,
8062 +                       &network_connections_key);
8063 +
8064 +  if (status != ERROR_SUCCESS)
8065 +    msg (M_FATAL, "Error opening registry key: %s", NETWORK_CONNECTIONS_KEY);
8066 +
8067 +  while (true)
8068 +    {
8069 +      char enum_name[256];
8070 +      char connection_string[256];
8071 +      HKEY connection_key;
8072 +      char name_data[256];
8073 +      DWORD name_type;
8074 +      const char name_string[] = "Name";
8075 +
8076 +      len = sizeof (enum_name);
8077 +      status = RegEnumKeyEx(
8078 +                           network_connections_key,
8079 +                           i,
8080 +                           enum_name,
8081 +                           &len,
8082 +                           NULL,
8083 +                           NULL,
8084 +                           NULL,
8085 +                           NULL);
8086 +      if (status == ERROR_NO_MORE_ITEMS)
8087 +       break;
8088 +      else if (status != ERROR_SUCCESS)
8089 +       msg (M_FATAL, "Error enumerating registry subkeys of key: %s",
8090 +            NETWORK_CONNECTIONS_KEY);
8091 +
8092 +      openvpn_snprintf (connection_string, sizeof(connection_string),
8093 +                       "%s\\%s\\Connection",
8094 +                       NETWORK_CONNECTIONS_KEY, enum_name);
8095 +
8096 +      status = RegOpenKeyEx(
8097 +                           HKEY_LOCAL_MACHINE,
8098 +                           connection_string,
8099 +                           0,
8100 +                           KEY_READ,
8101 +                           &connection_key);
8102 +
8103 +      if (status != ERROR_SUCCESS)
8104 +       dmsg (D_REGISTRY, "Error opening registry key: %s", connection_string);
8105 +      else
8106 +       {
8107 +         len = sizeof (name_data);
8108 +         status = RegQueryValueEx(
8109 +                                  connection_key,
8110 +                                  name_string,
8111 +                                  NULL,
8112 +                                  &name_type,
8113 +                                  name_data,
8114 +                                  &len);
8115 +
8116 +         if (status != ERROR_SUCCESS || name_type != REG_SZ)
8117 +           dmsg (D_REGISTRY, "Error opening registry key: %s\\%s\\%s",
8118 +                NETWORK_CONNECTIONS_KEY, connection_string, name_string);
8119 +         else
8120 +           {
8121 +             struct panel_reg *reg;
8122 +
8123 +             ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc);
8124 +             reg->name = string_alloc (name_data, gc);
8125 +             reg->guid = string_alloc (enum_name, gc);
8126 +                     
8127 +             /* link into return list */
8128 +             if (!first)
8129 +               first = reg;
8130 +             if (last)
8131 +               last->next = reg;
8132 +             last = reg;
8133 +           }
8134 +         RegCloseKey (connection_key);
8135 +       }
8136 +      ++i;
8137 +    }
8138 +
8139 +  RegCloseKey (network_connections_key);
8140 +
8141 +  return first;
8142 +}
8143 +
8144 +/*
8145 + * Check that two addresses are part of the same 255.255.255.252 subnet.
8146 + */
8147 +void
8148 +verify_255_255_255_252 (in_addr_t local, in_addr_t remote)
8149 +{
8150 +  struct gc_arena gc = gc_new ();
8151 +  const unsigned int mask = 3;
8152 +  const char *err = NULL;
8153 +
8154 +  if (local == remote)
8155 +    {
8156 +      err = "must be different";
8157 +      goto error;
8158 +    }
8159 +  if ((local & (~mask)) != (remote & (~mask)))
8160 +    {
8161 +      err = "must exist within the same 255.255.255.252 subnet.  This is a limitation of --dev tun when used with the TAP-WIN32 driver";
8162 +      goto error;
8163 +    }
8164 +  if ((local & mask) == 0
8165 +      || (local & mask) == 3
8166 +      || (remote & mask) == 0
8167 +      || (remote & mask) == 3)
8168 +    {
8169 +      err = "cannot use the first or last address within a given 255.255.255.252 subnet.  This is a limitation of --dev tun when used with the TAP-WIN32 driver";
8170 +      goto error;
8171 +    }
8172 +
8173 +  gc_free (&gc);
8174 +  return;
8175 +
8176 + error:
8177 +  msg (M_FATAL, "There is a problem in your selection of --ifconfig endpoints [local=%s, remote=%s].  The local and remote VPN endpoints %s.  Try '" PACKAGE " --show-valid-subnets' option for more info.",
8178 +       print_in_addr_t (local, 0, &gc),
8179 +       print_in_addr_t (remote, 0, &gc),
8180 +       err);
8181 +  gc_free (&gc);
8182 +}
8183 +
8184 +void show_valid_win32_tun_subnets (void)
8185 +{
8186 +  int i;
8187 +  int col = 0;
8188 +
8189 +  printf ("On Windows, point-to-point IP support (i.e. --dev tun)\n");
8190 +  printf ("is emulated by the TAP-Win32 driver.  The major limitation\n");
8191 +  printf ("imposed by this approach is that the --ifconfig local and\n");
8192 +  printf ("remote endpoints must be part of the same 255.255.255.252\n");
8193 +  printf ("subnet.  The following list shows examples of endpoint\n");
8194 +  printf ("pairs which satisfy this requirement.  Only the final\n");
8195 +  printf ("component of the IP address pairs is at issue.\n\n");
8196 +  printf ("As an example, the following option would be correct:\n");
8197 +  printf ("    --ifconfig 10.7.0.5 10.7.0.6 (on host A)\n");
8198 +  printf ("    --ifconfig 10.7.0.6 10.7.0.5 (on host B)\n");
8199 +  printf ("because [5,6] is part of the below list.\n\n");
8200 +
8201 +  for (i = 0; i < 256; i += 4)
8202 +    {
8203 +      printf("[%3d,%3d] ", i+1, i+2);
8204 +      if (++col > 4)
8205 +       {
8206 +         col = 0;
8207 +         printf ("\n");
8208 +       }
8209 +    }
8210 +  if (col)
8211 +    printf ("\n");
8212 +}
8213 +
8214 +void
8215 +show_tap_win32_adapters (int msglev, int warnlev)
8216 +{
8217 +  struct gc_arena gc = gc_new ();
8218 +
8219 +  bool warn_panel_null = false;
8220 +  bool warn_panel_dup = false;
8221 +  bool warn_tap_dup = false;
8222 +
8223 +  int links;
8224 +
8225 +  const struct tap_reg *tr;
8226 +  const struct tap_reg *tr1;
8227 +  const struct panel_reg *pr;
8228 +
8229 +  const struct tap_reg *tap_reg = get_tap_reg (&gc);
8230 +  const struct panel_reg *panel_reg = get_panel_reg (&gc);
8231 +
8232 +  msg (msglev, "Available TAP-WIN32 adapters [name, GUID]:");
8233 +
8234 +  /* loop through each TAP-Win32 adapter registry entry */
8235 +  for (tr = tap_reg; tr != NULL; tr = tr->next)
8236 +    {
8237 +      links = 0;
8238 +
8239 +      /* loop through each network connections entry in the control panel */
8240 +      for (pr = panel_reg; pr != NULL; pr = pr->next)
8241 +       {
8242 +         if (!strcmp (tr->guid, pr->guid))
8243 +           {
8244 +             msg (msglev, "'%s' %s", pr->name, tr->guid);
8245 +             ++links;
8246 +           }
8247 +       }
8248 +
8249 +      if (links > 1)
8250 +       {
8251 +         warn_panel_dup = true;
8252 +       }
8253 +      else if (links == 0)
8254 +       {
8255 +         /* a TAP adapter exists without a link from the network
8256 +            connections control panel */
8257 +         warn_panel_null = true;
8258 +         msg (msglev, "[NULL] %s", tr->guid);
8259 +       }
8260 +    }
8261 +
8262 +  /* check for TAP-Win32 adapter duplicated GUIDs */
8263 +  for (tr = tap_reg; tr != NULL; tr = tr->next)
8264 +    {
8265 +      for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next)
8266 +       {
8267 +         if (tr != tr1 && !strcmp (tr->guid, tr1->guid))
8268 +           warn_tap_dup = true;
8269 +       }
8270 +    }
8271 +
8272 +  /* warn on registry inconsistencies */
8273 +  if (warn_tap_dup)
8274 +    msg (warnlev, "WARNING: Some TAP-Win32 adapters have duplicate GUIDs");
8275 +
8276 +  if (warn_panel_dup)
8277 +    msg (warnlev, "WARNING: Some TAP-Win32 adapters have duplicate links from the Network Connections control panel");
8278 +
8279 +  if (warn_panel_null)
8280 +    msg (warnlev, "WARNING: Some TAP-Win32 adapters have no link from the Network Connections control panel");
8281 +
8282 +  gc_free (&gc);
8283 +}
8284 +
8285 +/*
8286 + * Confirm that GUID is a TAP-Win32 adapter.
8287 + */
8288 +static bool
8289 +is_tap_win32 (const char *guid, const struct tap_reg *tap_reg)
8290 +{
8291 +  const struct tap_reg *tr;
8292 +
8293 +  for (tr = tap_reg; tr != NULL; tr = tr->next)
8294 +    {
8295 +      if (guid && !strcmp (tr->guid, guid))
8296 +       return true;
8297 +    }
8298 +
8299 +  return false;
8300 +}
8301 +
8302 +static const char *
8303 +guid_to_name (const char *guid, const struct panel_reg *panel_reg)
8304 +{
8305 +  const struct panel_reg *pr;
8306 +
8307 +  for (pr = panel_reg; pr != NULL; pr = pr->next)
8308 +    {
8309 +      if (guid && !strcmp (pr->guid, guid))
8310 +       return pr->name;
8311 +    }
8312 +
8313 +  return NULL;
8314 +}
8315 +
8316 +static const char *
8317 +name_to_guid (const char *name, const struct tap_reg *tap_reg, const struct panel_reg *panel_reg)
8318 +{
8319 +  const struct panel_reg *pr;
8320 +
8321 +  for (pr = panel_reg; pr != NULL; pr = pr->next)
8322 +    {
8323 +      if (name && !strcmp (pr->name, name) && is_tap_win32 (pr->guid, tap_reg))
8324 +       return pr->guid;
8325 +    }
8326 +
8327 +  return NULL;
8328 +}
8329 +
8330 +static void
8331 +at_least_one_tap_win32 (const struct tap_reg *tap_reg)
8332 +{
8333 +  if (!tap_reg)
8334 +    msg (M_FATAL, "There are no TAP-Win32 adapters on this system.  You should be able to create a TAP-Win32 adapter by going to Start -> All Programs -> " PACKAGE_NAME " -> Add a new TAP-Win32 virtual ethernet adapter.");
8335 +}
8336 +
8337 +/*
8338 + * Get an adapter GUID and optional actual_name from the 
8339 + * registry for the TAP device # = device_number.
8340 + */
8341 +static const char *
8342 +get_unspecified_device_guid (const int device_number,
8343 +                            char *actual_name,
8344 +                            int actual_name_size,
8345 +                            const struct tap_reg *tap_reg_src,
8346 +                            const struct panel_reg *panel_reg_src,
8347 +                            struct gc_arena *gc)
8348 +{
8349 +  const struct tap_reg *tap_reg = tap_reg_src;
8350 +  struct buffer ret = clear_buf ();
8351 +  struct buffer actual = clear_buf ();
8352 +  int i;
8353 +
8354 +  ASSERT (device_number >= 0);
8355 +
8356 +  /* Make sure we have at least one TAP adapter */
8357 +  if (!tap_reg)
8358 +    return NULL;
8359 +
8360 +  /* The actual_name output buffer may be NULL */
8361 +  if (actual_name)
8362 +    {
8363 +      ASSERT (actual_name_size > 0);
8364 +      buf_set_write (&actual, actual_name, actual_name_size);
8365 +    }
8366 +
8367 +  /* Move on to specified device number */
8368 +  for (i = 0; i < device_number; i++)
8369 +    {
8370 +      tap_reg = tap_reg->next;
8371 +      if (!tap_reg)
8372 +       return NULL;
8373 +    }
8374 +
8375 +  /* Save Network Panel name (if exists) in actual_name */
8376 +  if (actual_name)
8377 +    {
8378 +      const char *act = guid_to_name (tap_reg->guid, panel_reg_src);
8379 +      if (act)
8380 +       buf_printf (&actual, "%s", act);
8381 +      else
8382 +       buf_printf (&actual, "%s", tap_reg->guid);
8383 +    }
8384 +
8385 +  /* Save GUID for return value */
8386 +  ret = alloc_buf_gc (256, gc);
8387 +  buf_printf (&ret, "%s", tap_reg->guid);
8388 +  return BSTR (&ret);
8389 +}
8390 +
8391 +/*
8392 + * Lookup a --dev-node adapter name in the registry
8393 + * returning the GUID and optional actual_name.
8394 + */
8395 +static const char *
8396 +get_device_guid (const char *name,
8397 +                char *actual_name,
8398 +                int actual_name_size,
8399 +                const struct tap_reg *tap_reg,
8400 +                const struct panel_reg *panel_reg,
8401 +                struct gc_arena *gc)
8402 +{
8403 +  struct buffer ret = alloc_buf_gc (256, gc);
8404 +  struct buffer actual = clear_buf ();
8405 +
8406 +  /* Make sure we have at least one TAP adapter */
8407 +  if (!tap_reg)
8408 +    return NULL;
8409 +
8410 +  /* The actual_name output buffer may be NULL */
8411 +  if (actual_name)
8412 +    {
8413 +      ASSERT (actual_name_size > 0);
8414 +      buf_set_write (&actual, actual_name, actual_name_size);
8415 +    }
8416 +
8417 +  /* Check if GUID was explicitly specified as --dev-node parameter */
8418 +  if (is_tap_win32 (name, tap_reg))
8419 +    {
8420 +      const char *act = guid_to_name (name, panel_reg);
8421 +      buf_printf (&ret, "%s", name);
8422 +      if (act)
8423 +       buf_printf (&actual, "%s", act);
8424 +      else
8425 +       buf_printf (&actual, "%s", name);
8426 +      return BSTR (&ret);
8427 +    }
8428 +
8429 +  /* Lookup TAP adapter in network connections list */
8430 +  {
8431 +    const char *guid = name_to_guid (name, tap_reg, panel_reg);
8432 +    if (guid)
8433 +      {
8434 +       buf_printf (&actual, "%s", name);
8435 +       buf_printf (&ret, "%s", guid);
8436 +       return BSTR (&ret);
8437 +      }
8438 +  }
8439 +
8440 +  return NULL;
8441 +}
8442 +
8443 +/*
8444 + * Get adapter info list
8445 + */
8446 +const IP_ADAPTER_INFO *
8447 +get_adapter_info_list (struct gc_arena *gc)
8448 +{
8449 +  ULONG size = 0;
8450 +  IP_ADAPTER_INFO *pi = NULL;
8451 +  DWORD status;
8452 +
8453 +  if ((status = GetAdaptersInfo (NULL, &size)) != ERROR_BUFFER_OVERFLOW)
8454 +    {
8455 +      msg (M_INFO, "GetAdaptersInfo #1 failed (status=%u) : %s",
8456 +          (unsigned int)status,
8457 +          strerror_win32 (status, gc));
8458 +    }
8459 +  else
8460 +    {
8461 +      pi = (PIP_ADAPTER_INFO) gc_malloc (size, false, gc);
8462 +      if ((status = GetAdaptersInfo (pi, &size)) == NO_ERROR)
8463 +       return pi;
8464 +      else
8465 +       {
8466 +         msg (M_INFO, "GetAdaptersInfo #2 failed (status=%u) : %s",
8467 +              (unsigned int)status,
8468 +              strerror_win32 (status, gc));
8469 +       }
8470 +    }
8471 +  return pi;
8472 +}
8473 +
8474 +const IP_PER_ADAPTER_INFO *
8475 +get_per_adapter_info (const DWORD index, struct gc_arena *gc)
8476 +{
8477 +  ULONG size = 0;
8478 +  IP_PER_ADAPTER_INFO *pi = NULL;
8479 +  DWORD status;
8480 +
8481 +  if (index != ~0)
8482 +    {
8483 +      if ((status = GetPerAdapterInfo (index, NULL, &size)) != ERROR_BUFFER_OVERFLOW)
8484 +       {
8485 +         msg (M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s",
8486 +              (unsigned int)status,
8487 +              strerror_win32 (status, gc));
8488 +       }
8489 +      else
8490 +       {
8491 +         pi = (PIP_PER_ADAPTER_INFO) gc_malloc (size, false, gc);
8492 +         if ((status = GetPerAdapterInfo ((ULONG)index, pi, &size)) == ERROR_SUCCESS)
8493 +           return pi;
8494 +         else
8495 +           {
8496 +             msg (M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s",
8497 +                  (unsigned int)status,
8498 +                  strerror_win32 (status, gc));
8499 +           }
8500 +       }
8501 +    }
8502 +  return pi;
8503 +}
8504 +
8505 +static const IP_INTERFACE_INFO *
8506 +get_interface_info_list (struct gc_arena *gc)
8507 +{
8508 +  ULONG size = 0;
8509 +  IP_INTERFACE_INFO *ii = NULL;
8510 +  DWORD status;
8511 +
8512 +  if ((status = GetInterfaceInfo (NULL, &size)) != ERROR_INSUFFICIENT_BUFFER)
8513 +    {
8514 +      msg (M_INFO, "GetInterfaceInfo #1 failed (status=%u) : %s",
8515 +          (unsigned int)status,
8516 +          strerror_win32 (status, gc));
8517 +    }
8518 +  else
8519 +    {
8520 +      ii = (PIP_INTERFACE_INFO) gc_malloc (size, false, gc);
8521 +      if ((status = GetInterfaceInfo (ii, &size)) == NO_ERROR)
8522 +       return ii;
8523 +      else
8524 +       {
8525 +         msg (M_INFO, "GetInterfaceInfo #2 failed (status=%u) : %s",
8526 +              (unsigned int)status,
8527 +              strerror_win32 (status, gc));
8528 +       }
8529 +    }
8530 +  return ii;
8531 +}
8532 +
8533 +static const IP_ADAPTER_INDEX_MAP *
8534 +get_interface_info (DWORD index, struct gc_arena *gc)
8535 +{
8536 +  const IP_INTERFACE_INFO *list = get_interface_info_list (gc);
8537 +  if (list)
8538 +    {
8539 +      int i;
8540 +      for (i = 0; i < list->NumAdapters; ++i)
8541 +       {
8542 +         const IP_ADAPTER_INDEX_MAP *inter = &list->Adapter[i];
8543 +         if (index == inter->Index)
8544 +           return inter;
8545 +       }
8546 +    }
8547 +  return NULL;
8548 +}
8549 +
8550 +/*
8551 + * Given an adapter index, return a pointer to the
8552 + * IP_ADAPTER_INFO structure for that adapter.
8553 + */
8554 +
8555 +const IP_ADAPTER_INFO *
8556 +get_adapter (const IP_ADAPTER_INFO *ai, DWORD index)
8557 +{
8558 +  if (ai && index != (DWORD)~0)
8559 +    {
8560 +      const IP_ADAPTER_INFO *a;
8561 +
8562 +      /* find index in the linked list */
8563 +      for (a = ai; a != NULL; a = a->Next)
8564 +       {
8565 +         if (a->Index == index)
8566 +           return a;
8567 +       }
8568 +    }
8569 +  return NULL;
8570 +}
8571 +
8572 +const IP_ADAPTER_INFO *
8573 +get_adapter_info (DWORD index, struct gc_arena *gc)
8574 +{
8575 +  return get_adapter (get_adapter_info_list (gc), index);
8576 +}
8577 +
8578 +static int
8579 +get_adapter_n_ip_netmask (const IP_ADAPTER_INFO *ai)
8580 +{
8581 +  if (ai)
8582 +    {
8583 +      int n = 0;
8584 +      const IP_ADDR_STRING *ip = &ai->IpAddressList;
8585 +
8586 +      while (ip)
8587 +       {
8588 +         ++n;
8589 +         ip = ip->Next;
8590 +       }
8591 +      return n;
8592 +    }
8593 +  else
8594 +    return 0;
8595 +}
8596 +
8597 +static bool
8598 +get_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const int n, in_addr_t *ip, in_addr_t *netmask)
8599 +{
8600 +  bool ret = false;
8601 +  *ip = 0;
8602 +  *netmask = 0;
8603 +
8604 +  if (ai)
8605 +    {
8606 +      const IP_ADDR_STRING *iplist = &ai->IpAddressList;
8607 +      int i = 0;
8608 +
8609 +      while (iplist)
8610 +       {
8611 +         if (i == n)
8612 +           break;
8613 +         ++i;
8614 +         iplist = iplist->Next;
8615 +       }
8616 +
8617 +      if (iplist)
8618 +       {
8619 +         const unsigned int getaddr_flags = GETADDR_HOST_ORDER;
8620 +         const char *ip_str = iplist->IpAddress.String;
8621 +         const char *netmask_str = iplist->IpMask.String;
8622 +         bool succeed1 = false;
8623 +         bool succeed2 = false;
8624 +
8625 +         if (ip_str && netmask_str && strlen (ip_str) && strlen (netmask_str))
8626 +           {
8627 +             *ip = getaddr (getaddr_flags, ip_str, 0, &succeed1, NULL);
8628 +             *netmask = getaddr (getaddr_flags, netmask_str, 0, &succeed2, NULL);
8629 +             ret = (succeed1 == true && succeed2 == true);
8630 +           }
8631 +       }
8632 +    }
8633 +
8634 +  return ret;
8635 +}
8636 +
8637 +static bool
8638 +test_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const in_addr_t ip, const in_addr_t netmask)
8639 +{
8640 +  if (ai)
8641 +    {
8642 +      in_addr_t ip_adapter = 0;
8643 +      in_addr_t netmask_adapter = 0;
8644 +      const bool status = get_adapter_ip_netmask (ai, 0, &ip_adapter, &netmask_adapter);
8645 +      return (status && ip_adapter == ip && netmask_adapter == netmask);
8646 +    }
8647 +  else
8648 +    return false;
8649 +}
8650 +
8651 +const IP_ADAPTER_INFO *
8652 +get_tun_adapter (const struct tuntap *tt, const IP_ADAPTER_INFO *list)
8653 +{
8654 +  if (list && tt)
8655 +    return get_adapter (list, tt->adapter_index);
8656 +  else
8657 +    return NULL;
8658 +}
8659 +
8660 +bool
8661 +is_adapter_up (const struct tuntap *tt, const IP_ADAPTER_INFO *list)
8662 +{
8663 +  int i;
8664 +  bool ret = false;
8665 +
8666 +  const IP_ADAPTER_INFO *ai = get_tun_adapter (tt, list);
8667 +
8668 +  if (ai)
8669 +    {
8670 +      const int n = get_adapter_n_ip_netmask (ai);
8671 +
8672 +      /* loop once for every IP/netmask assigned to adapter */
8673 +      for (i = 0; i < n; ++i)
8674 +       {
8675 +         in_addr_t ip, netmask;
8676 +         if (get_adapter_ip_netmask (ai, i, &ip, &netmask))
8677 +           {
8678 +             if (tt->local && tt->adapter_netmask)
8679 +               {
8680 +                 /* wait for our --ifconfig parms to match the actual adapter parms */
8681 +                 if (tt->local == ip && tt->adapter_netmask == netmask)
8682 +                   ret = true;
8683 +               }
8684 +             else
8685 +               {
8686 +                 /* --ifconfig was not defined, maybe using a real DHCP server */
8687 +                 if (ip && netmask)
8688 +                   ret = true;
8689 +               }
8690 +           }
8691 +       }
8692 +    }
8693 +  else
8694 +    ret = true; /* this can occur when TAP adapter is bridged */
8695 +
8696 +  return ret;
8697 +}
8698 +
8699 +bool
8700 +is_ip_in_adapter_subnet (const IP_ADAPTER_INFO *ai, const in_addr_t ip, in_addr_t *highest_netmask)
8701 +{
8702 +  int i;
8703 +  bool ret = false;
8704 +
8705 +  if (highest_netmask)
8706 +    *highest_netmask = 0;
8707 +
8708 +  if (ai)
8709 +    {
8710 +      const int n = get_adapter_n_ip_netmask (ai);
8711 +      for (i = 0; i < n; ++i)
8712 +       {
8713 +         in_addr_t adapter_ip, adapter_netmask;
8714 +         if (get_adapter_ip_netmask (ai, i, &adapter_ip, &adapter_netmask))
8715 +           {
8716 +             if (adapter_ip && adapter_netmask && (ip & adapter_netmask) == (adapter_ip & adapter_netmask))
8717 +               {
8718 +                 if (highest_netmask && adapter_netmask > *highest_netmask)
8719 +                   *highest_netmask = adapter_netmask;
8720 +                 ret = true;
8721 +               }
8722 +           }
8723 +       }
8724 +    }
8725 +  return ret;
8726 +}
8727 +
8728 +DWORD
8729 +adapter_index_of_ip (const IP_ADAPTER_INFO *list,
8730 +                    const in_addr_t ip,
8731 +                    int *count,
8732 +                    in_addr_t *netmask)
8733 +{
8734 +  struct gc_arena gc = gc_new ();
8735 +  DWORD ret = ~0;
8736 +  in_addr_t highest_netmask = 0;
8737 +  bool first = true;
8738 +
8739 +  if (count)
8740 +    *count = 0;
8741 +
8742 +  while (list)
8743 +    {
8744 +      in_addr_t hn;
8745 +
8746 +      if (is_ip_in_adapter_subnet (list, ip, &hn))
8747 +       {
8748 +         if (first || hn > highest_netmask)
8749 +           {
8750 +             highest_netmask = hn;
8751 +             if (count)
8752 +               *count = 1;
8753 +             ret = list->Index;
8754 +             first = false;
8755 +           }
8756 +         else if (hn == highest_netmask)
8757 +           {
8758 +             if (count)
8759 +               ++*count;
8760 +           }
8761 +       }
8762 +      list = list->Next;
8763 +    }
8764 +
8765 +  dmsg (D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d",
8766 +       print_in_addr_t (ip, 0, &gc),
8767 +       print_in_addr_t (highest_netmask, 0, &gc),
8768 +       (int)ret,
8769 +       count ? *count : -1);
8770 +
8771 +  if (ret == ~0 && count)
8772 +    *count = 0;
8773 +
8774 +  if (netmask)
8775 +    *netmask = highest_netmask;
8776 +
8777 +  gc_free (&gc);
8778 +  return ret;
8779 +}
8780 +
8781 +/*
8782 + * Given an adapter index, return true if the adapter
8783 + * is DHCP disabled.
8784 + */
8785 +
8786 +#define DHCP_STATUS_UNDEF     0
8787 +#define DHCP_STATUS_ENABLED   1
8788 +#define DHCP_STATUS_DISABLED  2
8789 +
8790 +static int
8791 +dhcp_status (DWORD index)
8792 +{
8793 +  struct gc_arena gc = gc_new ();
8794 +  int ret = DHCP_STATUS_UNDEF;
8795 +  if (index != ~0)
8796 +    {
8797 +      const IP_ADAPTER_INFO *ai = get_adapter_info (index, &gc);
8798 +
8799 +      if (ai)
8800 +       {
8801 +         if (ai->DhcpEnabled)
8802 +           ret = DHCP_STATUS_ENABLED;
8803 +         else
8804 +           ret = DHCP_STATUS_DISABLED;
8805 +       }
8806 +    }
8807 +  gc_free (&gc);
8808 +  return ret;
8809 +}
8810 +
8811 +/*
8812 + * Delete all temporary address/netmask pairs which were added
8813 + * to adapter (given by index) by previous calls to AddIPAddress.
8814 + */
8815 +static void
8816 +delete_temp_addresses (DWORD index)
8817 +{
8818 +  struct gc_arena gc = gc_new ();
8819 +  const IP_ADAPTER_INFO *a = get_adapter_info (index, &gc);
8820 +
8821 +  if (a)
8822 +    {
8823 +      const IP_ADDR_STRING *ip = &a->IpAddressList;
8824 +      while (ip)
8825 +       {
8826 +         DWORD status;
8827 +         const DWORD context = ip->Context;
8828 +
8829 +         if ((status = DeleteIPAddress ((ULONG) context)) == NO_ERROR)
8830 +           {
8831 +             msg (M_INFO, "Successfully deleted previously set dynamic IP/netmask: %s/%s",
8832 +                  ip->IpAddress.String,
8833 +                  ip->IpMask.String);
8834 +           }
8835 +         else
8836 +           {
8837 +             const char *empty = "0.0.0.0";
8838 +             if (strcmp (ip->IpAddress.String, empty)
8839 +                 || strcmp (ip->IpMask.String, empty))
8840 +               msg (M_INFO, "NOTE: could not delete previously set dynamic IP/netmask: %s/%s (status=%u)",
8841 +                    ip->IpAddress.String,
8842 +                    ip->IpMask.String,
8843 +                    (unsigned int)status);
8844 +           }
8845 +         ip = ip->Next;
8846 +       }
8847 +    }
8848 +  gc_free (&gc);
8849 +}
8850 +
8851 +/*
8852 + * Get interface index for use with IP Helper API functions.
8853 + */
8854 +static DWORD
8855 +get_adapter_index_method_1 (const char *guid)
8856 +{
8857 +  struct gc_arena gc = gc_new ();
8858 +  ULONG index = ~0;
8859 +  DWORD status;
8860 +  wchar_t wbuf[256];
8861 +  snwprintf (wbuf, SIZE (wbuf), L"\\DEVICE\\TCPIP_%S", guid);
8862 +  wbuf [SIZE(wbuf) - 1] = 0;
8863 +  if ((status = GetAdapterIndex (wbuf, &index)) != NO_ERROR)
8864 +    index = ~0;
8865 +  gc_free (&gc);
8866 +  return index;
8867 +}
8868 +
8869 +static DWORD
8870 +get_adapter_index_method_2 (const char *guid)
8871 +{
8872 +  struct gc_arena gc = gc_new ();
8873 +  DWORD index = ~0;
8874 +
8875 +  const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc);
8876 +
8877 +  while (list)
8878 +    {
8879 +      if (!strcmp (guid, list->AdapterName))
8880 +       {
8881 +         index = list->Index;
8882 +         break;
8883 +       }
8884 +      list = list->Next;
8885 +    }
8886 +
8887 +  gc_free (&gc);
8888 +  return index;
8889 +}
8890 +
8891 +static DWORD
8892 +get_adapter_index (const char *guid)
8893 +{
8894 +  DWORD index;
8895 +  index = get_adapter_index_method_1 (guid);
8896 +  if (index == ~0)
8897 +    index = get_adapter_index_method_2 (guid);
8898 +  if (index == ~0)
8899 +    msg (M_INFO, "NOTE: could not get adapter index for %s", guid);
8900 +  return index;
8901 +}
8902 +
8903 +static DWORD
8904 +get_adapter_index_flexible (const char *name) /* actual name or GUID */
8905 +{
8906 +  struct gc_arena gc = gc_new ();
8907 +  DWORD index;
8908 +  index = get_adapter_index_method_1 (name);
8909 +  if (index == ~0)
8910 +    index = get_adapter_index_method_2 (name);
8911 +  if (index == ~0)
8912 +    {
8913 +      const struct tap_reg *tap_reg = get_tap_reg (&gc);
8914 +      const struct panel_reg *panel_reg = get_panel_reg (&gc);
8915 +      const char *guid = name_to_guid (name, tap_reg, panel_reg);
8916 +      index = get_adapter_index_method_1 (guid);
8917 +      if (index == ~0)
8918 +       index = get_adapter_index_method_2 (guid);
8919 +    }
8920 +  if (index == ~0)
8921 +    msg (M_INFO, "NOTE: could not get adapter index for name/GUID '%s'", name);
8922 +  gc_free (&gc);
8923 +  return index;
8924 +}
8925 +
8926 +/*
8927 + * Return a string representing a PIP_ADDR_STRING
8928 + */
8929 +static const char *
8930 +format_ip_addr_string (const IP_ADDR_STRING *ip, struct gc_arena *gc)
8931 +{
8932 +  struct buffer out = alloc_buf_gc (256, gc);
8933 +  while (ip)
8934 +    {
8935 +      buf_printf (&out, "%s", ip->IpAddress.String);
8936 +      if (strlen (ip->IpMask.String))
8937 +       {
8938 +         buf_printf (&out, "/");
8939 +         buf_printf (&out, "%s", ip->IpMask.String);
8940 +       }
8941 +      buf_printf (&out, " ");
8942 +      ip = ip->Next;
8943 +    }
8944 +  return BSTR (&out);
8945 +}
8946 +
8947 +/*
8948 + * Show info for a single adapter
8949 + */
8950 +static void
8951 +show_adapter (int msglev, const IP_ADAPTER_INFO *a, struct gc_arena *gc)
8952 +{
8953 +  msg (msglev, "%s", a->Description);
8954 +  msg (msglev, "  Index = %d", (int)a->Index);
8955 +  msg (msglev, "  GUID = %s", a->AdapterName);
8956 +  msg (msglev, "  IP = %s", format_ip_addr_string (&a->IpAddressList, gc));
8957 +  msg (msglev, "  MAC = %s", format_hex_ex (a->Address, a->AddressLength, 0, 1, ":", gc));
8958 +  msg (msglev, "  GATEWAY = %s", format_ip_addr_string (&a->GatewayList, gc));
8959 +  if (a->DhcpEnabled)
8960 +    {
8961 +      msg (msglev, "  DHCP SERV = %s", format_ip_addr_string (&a->DhcpServer, gc));
8962 +      msg (msglev, "  DHCP LEASE OBTAINED = %s", time_string (a->LeaseObtained, 0, false, gc));
8963 +      msg (msglev, "  DHCP LEASE EXPIRES  = %s", time_string (a->LeaseExpires, 0, false, gc));
8964 +    }
8965 +  if (a->HaveWins)
8966 +    {
8967 +      msg (msglev, "  PRI WINS = %s", format_ip_addr_string (&a->PrimaryWinsServer, gc));
8968 +      msg (msglev, "  SEC WINS = %s", format_ip_addr_string (&a->SecondaryWinsServer, gc));
8969 +    }
8970 +
8971 +  {
8972 +    const IP_PER_ADAPTER_INFO *pai = get_per_adapter_info (a->Index, gc);
8973 +    if (pai)
8974 +      {
8975 +       msg (msglev, "  DNS SERV = %s", format_ip_addr_string (&pai->DnsServerList, gc));
8976 +      }
8977 +  }
8978 +}
8979 +
8980 +/*
8981 + * Show current adapter list
8982 + */
8983 +void
8984 +show_adapters (int msglev)
8985 +{
8986 +  struct gc_arena gc = gc_new ();
8987 +  const IP_ADAPTER_INFO *ai = get_adapter_info_list (&gc);
8988 +
8989 +  msg (msglev, "SYSTEM ADAPTER LIST");
8990 +  if (ai)
8991 +    {
8992 +      const IP_ADAPTER_INFO *a;
8993 +
8994 +      /* find index in the linked list */
8995 +      for (a = ai; a != NULL; a = a->Next)
8996 +       {
8997 +         show_adapter (msglev, a, &gc);
8998 +       }
8999 +    }
9000 +  gc_free (&gc);
9001 +}
9002 +
9003 +/*
9004 + * Set a particular TAP-Win32 adapter (or all of them if
9005 + * adapter_name == NULL) to allow it to be opened from
9006 + * a non-admin account.  This setting will only persist
9007 + * for the lifetime of the device object.
9008 + */
9009 +
9010 +static void
9011 +tap_allow_nonadmin_access_handle (const char *device_path, HANDLE hand)
9012 +{
9013 +  struct security_attributes sa;
9014 +  BOOL status;
9015 +
9016 +  if (!init_security_attributes_allow_all (&sa))
9017 +    msg (M_ERR, "Error: init SA failed");
9018 +
9019 +  status = SetKernelObjectSecurity (hand, DACL_SECURITY_INFORMATION, &sa.sd);
9020 +  if (!status)
9021 +    {
9022 +      msg (M_ERRNO, "Error: SetKernelObjectSecurity failed on %s", device_path);
9023 +    }
9024 +  else
9025 +    {
9026 +      msg (M_INFO|M_NOPREFIX, "TAP-Win32 device: %s [Non-admin access allowed]", device_path);
9027 +    }
9028 +}
9029 +
9030 +void
9031 +tap_allow_nonadmin_access (const char *dev_node)
9032 +{
9033 +  struct gc_arena gc = gc_new ();
9034 +  const struct tap_reg *tap_reg = get_tap_reg (&gc);
9035 +  const struct panel_reg *panel_reg = get_panel_reg (&gc);
9036 +  const char *device_guid = NULL;
9037 +  HANDLE hand;
9038 +  char actual_buffer[256];
9039 +  char device_path[256];
9040 +
9041 +  at_least_one_tap_win32 (tap_reg);
9042 +
9043 +  if (dev_node)
9044 +    {
9045 +      /* Get the device GUID for the device specified with --dev-node. */
9046 +      device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc);
9047 +
9048 +      if (!device_guid)
9049 +       msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node);
9050 +
9051 +      /* Open Windows TAP-Win32 adapter */
9052 +      openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s",
9053 +                       USERMODEDEVICEDIR,
9054 +                       device_guid,
9055 +                       TAPSUFFIX);
9056 +      
9057 +      hand = CreateFile (
9058 +                        device_path,
9059 +                        MAXIMUM_ALLOWED,
9060 +                        0, /* was: FILE_SHARE_READ */
9061 +                        0,
9062 +                        OPEN_EXISTING,
9063 +                        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
9064 +                        0
9065 +                        );
9066 +
9067 +      if (hand == INVALID_HANDLE_VALUE)
9068 +       msg (M_ERR, "CreateFile failed on TAP device: %s", device_path);
9069 +
9070 +      tap_allow_nonadmin_access_handle (device_path, hand);
9071 +      CloseHandle (hand);
9072 +    }
9073 +  else 
9074 +    {
9075 +      int device_number = 0;
9076 +
9077 +      /* Try opening all TAP devices */
9078 +      while (true)
9079 +       {
9080 +         device_guid = get_unspecified_device_guid (device_number, 
9081 +                                                    actual_buffer, 
9082 +                                                    sizeof (actual_buffer),
9083 +                                                    tap_reg,
9084 +                                                    panel_reg,
9085 +                                                    &gc);
9086 +
9087 +         if (!device_guid)
9088 +           break;
9089 +
9090 +         /* Open Windows TAP-Win32 adapter */
9091 +         openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s",
9092 +                           USERMODEDEVICEDIR,
9093 +                           device_guid,
9094 +                           TAPSUFFIX);
9095 +
9096 +         hand = CreateFile (
9097 +                            device_path,
9098 +                            MAXIMUM_ALLOWED,
9099 +                            0, /* was: FILE_SHARE_READ */
9100 +                            0,
9101 +                            OPEN_EXISTING,
9102 +                            FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
9103 +                            0
9104 +                            );
9105 +
9106 +         if (hand == INVALID_HANDLE_VALUE)
9107 +           msg (M_WARN, "CreateFile failed on TAP device: %s", device_path);
9108 +         else
9109 +           {
9110 +             tap_allow_nonadmin_access_handle (device_path, hand);
9111 +             CloseHandle (hand);
9112 +           }
9113 +  
9114 +         device_number++;
9115 +       }
9116 +    }
9117 +  gc_free (&gc);
9118 +}
9119 +
9120 +/*
9121 + * DHCP release/renewal
9122 + */
9123 +bool
9124 +dhcp_release_by_adapter_index(const DWORD adapter_index)
9125 +{
9126 +  struct gc_arena gc = gc_new ();
9127 +  bool ret = false;
9128 +  const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
9129 +
9130 +  if (inter)
9131 +    {
9132 +      DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter);
9133 +      if (status == NO_ERROR)
9134 +       {
9135 +         msg (D_TUNTAP_INFO, "TAP: DHCP address released");
9136 +         ret = true;
9137 +       }
9138 +      else
9139 +       msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)",
9140 +            strerror_win32 (status, &gc),
9141 +            (unsigned int)status);
9142 +    }
9143 +
9144 +  gc_free (&gc);
9145 +  return ret;
9146 +}
9147 +
9148 +static bool
9149 +dhcp_release (const struct tuntap *tt)
9150 +{
9151 +  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
9152 +    return dhcp_release_by_adapter_index (tt->adapter_index);
9153 +  else
9154 +    return false;
9155 +}
9156 +
9157 +bool
9158 +dhcp_renew_by_adapter_index (const DWORD adapter_index)
9159 +{
9160 +  struct gc_arena gc = gc_new ();
9161 +  bool ret = false;
9162 +  const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
9163 +
9164 +  if (inter)
9165 +    {
9166 +      DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter);
9167 +      if (status == NO_ERROR)
9168 +       {
9169 +         msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded");
9170 +         ret = true;
9171 +       }
9172 +      else
9173 +       msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)",
9174 +            strerror_win32 (status, &gc),
9175 +            (unsigned int)status);
9176 +    }
9177 +  gc_free (&gc);
9178 +  return ret;
9179 +}
9180 +
9181 +static bool
9182 +dhcp_renew (const struct tuntap *tt)
9183 +{
9184 +  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
9185 +    return dhcp_renew_by_adapter_index (tt->adapter_index);
9186 +  else
9187 +    return false;
9188 +}
9189 +
9190 +/*
9191 + * netsh functions
9192 + */
9193 +
9194 +static void
9195 +netsh_command (const struct argv *a, int n)
9196 +{
9197 +  int i;
9198 +  for (i = 0; i < n; ++i)
9199 +    {
9200 +      bool status;
9201 +      openvpn_sleep (1);
9202 +      netcmd_semaphore_lock ();
9203 +      argv_msg_prefix (M_INFO, a, "NETSH");
9204 +      status = openvpn_execve_check (a, NULL, 0, "ERROR: netsh command failed");
9205 +      netcmd_semaphore_release ();
9206 +      if (status)
9207 +       return;
9208 +      openvpn_sleep (4);
9209 +    }
9210 +  msg (M_FATAL, "NETSH: command failed");
9211 +}
9212 +
9213 +void
9214 +ipconfig_register_dns (const struct env_set *es)
9215 +{
9216 +  struct argv argv;
9217 +  bool status;
9218 +  const char err[] = "ERROR: Windows ipconfig command failed";
9219 +
9220 +  msg (D_TUNTAP_INFO, "Start net commands...");
9221 +  netcmd_semaphore_lock ();
9222 +
9223 +  argv_init (&argv);
9224 +
9225 +  argv_printf (&argv, "%s%sc stop dnscache",
9226 +              get_win_sys_path(),
9227 +              WIN_NET_PATH_SUFFIX);
9228 +  argv_msg (D_TUNTAP_INFO, &argv);
9229 +  status = openvpn_execve_check (&argv, es, 0, err);
9230 +  argv_reset(&argv);
9231 +
9232 +  argv_printf (&argv, "%s%sc start dnscache",
9233 +              get_win_sys_path(),
9234 +              WIN_NET_PATH_SUFFIX);
9235 +  argv_msg (D_TUNTAP_INFO, &argv);
9236 +  status = openvpn_execve_check (&argv, es, 0, err);
9237 +  argv_reset(&argv);
9238 +
9239 +  argv_printf (&argv, "%s%sc /flushdns",
9240 +              get_win_sys_path(),
9241 +              WIN_IPCONFIG_PATH_SUFFIX);
9242 +  argv_msg (D_TUNTAP_INFO, &argv);
9243 +  status = openvpn_execve_check (&argv, es, 0, err);
9244 +  argv_reset(&argv);
9245 +
9246 +  argv_printf (&argv, "%s%sc /registerdns",
9247 +              get_win_sys_path(),
9248 +              WIN_IPCONFIG_PATH_SUFFIX);
9249 +  argv_msg (D_TUNTAP_INFO, &argv);
9250 +  status = openvpn_execve_check (&argv, es, 0, err);
9251 +  argv_reset(&argv);
9252 +
9253 +  netcmd_semaphore_release ();
9254 +  msg (D_TUNTAP_INFO, "End net commands...");
9255 +}
9256 +
9257 +void
9258 +ip_addr_string_to_array (in_addr_t *dest, int *dest_len, const IP_ADDR_STRING *src)
9259 +{
9260 +  int i = 0;
9261 +  while (src)
9262 +    {
9263 +      const unsigned int getaddr_flags = GETADDR_HOST_ORDER;
9264 +      const char *ip_str = src->IpAddress.String;
9265 +      in_addr_t ip = 0;
9266 +      bool succeed = false;
9267 +
9268 +      if (i >= *dest_len)
9269 +       break;
9270 +      if (!ip_str || !strlen (ip_str))
9271 +       break;
9272 +
9273 +      ip = getaddr (getaddr_flags, ip_str, 0, &succeed, NULL);
9274 +      if (!succeed)
9275 +       break;
9276 +      dest[i++] = ip;
9277 +
9278 +      src = src->Next;
9279 +    }
9280 +  *dest_len = i;
9281 +
9282 +#if 0
9283 + {
9284 +   struct gc_arena gc = gc_new ();
9285 +   msg (M_INFO, "ip_addr_string_to_array [%d]", *dest_len);
9286 +   for (i = 0; i < *dest_len; ++i)
9287 +     {
9288 +       msg (M_INFO, "%s", print_in_addr_t (dest[i], 0, &gc));
9289 +     }
9290 +   gc_free (&gc);
9291 + }
9292 +#endif
9293 +}
9294 +
9295 +static bool
9296 +ip_addr_one_to_one (const in_addr_t *a1, const int a1len, const IP_ADDR_STRING *ias)
9297 +{
9298 +  in_addr_t a2[8];
9299 +  int a2len = SIZE(a2);
9300 +  int i;
9301 +
9302 +  ip_addr_string_to_array (a2, &a2len, ias);
9303 +  /*msg (M_INFO, "a1len=%d a2len=%d", a1len, a2len);*/
9304 +  if (a1len != a2len)
9305 +    return false;
9306 +
9307 +  for (i = 0; i < a1len; ++i)
9308 +    {
9309 +      if (a1[i] != a2[i])
9310 +       return false;
9311 +    }
9312 +  return true;
9313 +}
9314 +
9315 +static bool
9316 +ip_addr_member_of (const in_addr_t addr, const IP_ADDR_STRING *ias)
9317 +{
9318 +  in_addr_t aa[8];
9319 +  int len = SIZE(aa);
9320 +  int i;
9321 +
9322 +  ip_addr_string_to_array (aa, &len, ias);
9323 +  for (i = 0; i < len; ++i)
9324 +    {
9325 +      if (addr == aa[i])
9326 +       return true;
9327 +    }
9328 +  return false;
9329 +}
9330 +
9331 +static void
9332 +netsh_ifconfig_options (const char *type,
9333 +                       const in_addr_t *addr_list,
9334 +                       const int addr_len,
9335 +                       const IP_ADDR_STRING *current,
9336 +                       const char *flex_name,
9337 +                       const bool test_first)
9338 +{
9339 +  struct gc_arena gc = gc_new ();
9340 +  struct argv argv = argv_new ();
9341 +  bool delete_first = false;
9342 +
9343 +  /* first check if we should delete existing DNS/WINS settings from TAP interface */
9344 +  if (test_first)
9345 +    {
9346 +      if (!ip_addr_one_to_one (addr_list, addr_len, current))
9347 +       delete_first = true;
9348 +    }
9349 +  else
9350 +    delete_first = true;
9351 +  
9352 +  /* delete existing DNS/WINS settings from TAP interface */
9353 +  if (delete_first)
9354 +    {
9355 +      argv_printf (&argv, "%s%sc interface ip delete %s %s all",
9356 +                  get_win_sys_path(),
9357 +                  NETSH_PATH_SUFFIX,
9358 +                  type,
9359 +                  flex_name);
9360 +      netsh_command (&argv, 2);
9361 +    }
9362 +
9363 +  /* add new DNS/WINS settings to TAP interface */
9364 +  {
9365 +    int count = 0;
9366 +    int i;
9367 +    for (i = 0; i < addr_len; ++i)
9368 +      {
9369 +       if (delete_first || !test_first || !ip_addr_member_of (addr_list[i], current))
9370 +         {
9371 +           const char *fmt = count ?
9372 +               "%s%sc interface ip add %s %s %s"
9373 +             : "%s%sc interface ip set %s %s static %s";
9374 +
9375 +           argv_printf (&argv, fmt,
9376 +                        get_win_sys_path(),
9377 +                        NETSH_PATH_SUFFIX,
9378 +                        type,
9379 +                        flex_name,
9380 +                        print_in_addr_t (addr_list[i], 0, &gc));
9381 +           netsh_command (&argv, 2);
9382 +         
9383 +           ++count;
9384 +         }
9385 +       else
9386 +         {
9387 +           msg (M_INFO, "NETSH: \"%s\" %s %s [already set]",
9388 +                flex_name,
9389 +                type,
9390 +                print_in_addr_t (addr_list[i], 0, &gc));
9391 +         }
9392 +      }
9393 +  }
9394 +
9395 +  argv_reset (&argv);
9396 +  gc_free (&gc);
9397 +}
9398 +
9399 +static void
9400 +init_ip_addr_string2 (IP_ADDR_STRING *dest, const IP_ADDR_STRING *src1, const IP_ADDR_STRING *src2)
9401 +{
9402 +  CLEAR (dest[0]);
9403 +  CLEAR (dest[1]);
9404 +  if (src1)
9405 +    {
9406 +      dest[0] = *src1;
9407 +      dest[0].Next = NULL;
9408 +    }
9409 +  if (src2)
9410 +    {
9411 +      dest[1] = *src2;
9412 +      dest[0].Next = &dest[1];
9413 +      dest[1].Next = NULL;
9414 +    }
9415 +}
9416 +
9417 +static void
9418 +netsh_ifconfig (const struct tuntap_options *to,
9419 +               const char *flex_name,
9420 +               const in_addr_t ip,
9421 +               const in_addr_t netmask,
9422 +               const unsigned int flags)
9423 +{
9424 +  struct gc_arena gc = gc_new ();
9425 +  struct argv argv = argv_new ();
9426 +  const IP_ADAPTER_INFO *ai = NULL;
9427 +  const IP_PER_ADAPTER_INFO *pai = NULL;
9428 +
9429 +  if (flags & NI_TEST_FIRST)
9430 +    {
9431 +      const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc);
9432 +      const int index = get_adapter_index_flexible (flex_name);
9433 +      ai = get_adapter (list, index);
9434 +      pai = get_per_adapter_info (index, &gc);
9435 +    }
9436 +
9437 +  if (flags & NI_IP_NETMASK)
9438 +    {
9439 +      if (test_adapter_ip_netmask (ai, ip, netmask))
9440 +       {
9441 +         msg (M_INFO, "NETSH: \"%s\" %s/%s [already set]",
9442 +              flex_name,
9443 +              print_in_addr_t (ip, 0, &gc),
9444 +              print_in_addr_t (netmask, 0, &gc));
9445 +       }
9446 +      else
9447 +       {
9448 +         /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */
9449 +         argv_printf (&argv, "%s%sc interface ip set address %s static %s %s",
9450 +                      get_win_sys_path(),
9451 +                      NETSH_PATH_SUFFIX,
9452 +                      flex_name,
9453 +                      print_in_addr_t (ip, 0, &gc),
9454 +                      print_in_addr_t (netmask, 0, &gc));
9455 +
9456 +         netsh_command (&argv, 4);
9457 +       }
9458 +    }
9459 +
9460 +  /* set WINS/DNS options */
9461 +  if (flags & NI_OPTIONS)
9462 +    {
9463 +      IP_ADDR_STRING wins[2];
9464 +      CLEAR (wins[0]);
9465 +      CLEAR (wins[1]);
9466 +
9467 +      netsh_ifconfig_options ("dns",
9468 +                             to->dns,
9469 +                             to->dns_len,
9470 +                             pai ? &pai->DnsServerList : NULL,
9471 +                             flex_name,
9472 +                             BOOL_CAST (flags & NI_TEST_FIRST));
9473 +      if (ai && ai->HaveWins)
9474 +       init_ip_addr_string2 (wins, &ai->PrimaryWinsServer, &ai->SecondaryWinsServer);
9475 +
9476 +      netsh_ifconfig_options ("wins",
9477 +                             to->wins,
9478 +                             to->wins_len,
9479 +                             ai ? wins : NULL,
9480 +                             flex_name,
9481 +                             BOOL_CAST (flags & NI_TEST_FIRST));
9482 +    }
9483 +  
9484 +  argv_reset (&argv);
9485 +  gc_free (&gc);
9486 +}
9487 +
9488 +static void
9489 +netsh_enable_dhcp (const struct tuntap_options *to,
9490 +                  const char *actual_name)
9491 +{
9492 +  struct argv argv;
9493 +  argv_init (&argv);
9494 +
9495 +  /* example: netsh interface ip set address my-tap dhcp */
9496 +  argv_printf (&argv,
9497 +             "%s%sc interface ip set address %s dhcp",
9498 +              get_win_sys_path(),
9499 +              NETSH_PATH_SUFFIX,
9500 +              actual_name);
9501 +
9502 +  netsh_command (&argv, 4);
9503 +
9504 +  argv_reset (&argv);
9505 +}
9506 +
9507 +/*
9508 + * Return a TAP name for netsh commands.
9509 + */
9510 +static const char *
9511 +netsh_get_id (const char *dev_node, struct gc_arena *gc)
9512 +{
9513 +  const struct tap_reg *tap_reg = get_tap_reg (gc);
9514 +  const struct panel_reg *panel_reg = get_panel_reg (gc);
9515 +  struct buffer actual = alloc_buf_gc (256, gc);
9516 +  const char *guid;
9517 +
9518 +  at_least_one_tap_win32 (tap_reg);
9519 +
9520 +  if (dev_node)
9521 +    {
9522 +      guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc);
9523 +    }
9524 +  else
9525 +    {
9526 +      guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc);
9527 +
9528 +      if (get_unspecified_device_guid (1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Win32 adapter */
9529 +       guid = NULL;
9530 +    }
9531 +
9532 +  if (!guid)
9533 +    return "NULL";         /* not found */
9534 +  else if (strcmp (BPTR (&actual), "NULL"))
9535 +    return BPTR (&actual); /* control panel name */
9536 +  else
9537 +    return guid;           /* no control panel name, return GUID instead */
9538 +}
9539 +
9540 +/*
9541 + * Called iteratively on TAP-Win32 wait-for-initialization polling loop
9542 + */
9543 +void
9544 +tun_standby_init (struct tuntap *tt)
9545 +{
9546 +  tt->standby_iter = 0;
9547 +}
9548 +
9549 +bool
9550 +tun_standby (struct tuntap *tt)
9551 +{
9552 +  bool ret = true;
9553 +  ++tt->standby_iter;
9554 +  if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
9555 +    {
9556 +      if (tt->standby_iter == IPW32_SET_ADAPTIVE_TRY_NETSH)
9557 +       {
9558 +         msg (M_INFO, "NOTE: now trying netsh (this may take some time)");
9559 +         netsh_ifconfig (&tt->options,
9560 +                         tt->actual_name,
9561 +                         tt->local,
9562 +                         tt->adapter_netmask,
9563 +                         NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS);
9564 +       }
9565 +      else if (tt->standby_iter >= IPW32_SET_ADAPTIVE_TRY_NETSH*2)
9566 +       {
9567 +         ret = false;
9568 +       }
9569 +    }
9570 +  return ret;
9571 +}
9572 +
9573 +/*
9574 + * Convert DHCP options from the command line / config file
9575 + * into a raw DHCP-format options string.
9576 + */
9577 +
9578 +static void
9579 +write_dhcp_u8 (struct buffer *buf, const int type, const int data, bool *error)
9580 +{
9581 +  if (!buf_safe (buf, 3))
9582 +    {
9583 +      *error = true;
9584 +      msg (M_WARN, "write_dhcp_u8: buffer overflow building DHCP options");
9585 +      return;
9586 +    }
9587 +  buf_write_u8 (buf, type);
9588 +  buf_write_u8 (buf, 1);
9589 +  buf_write_u8 (buf, data);
9590 +}
9591 +
9592 +static void
9593 +write_dhcp_u32_array (struct buffer *buf, const int type, const uint32_t *data, const unsigned int len, bool *error)
9594 +{
9595 +  if (len > 0)
9596 +    {
9597 +      int i;
9598 +      const int size = len * sizeof (uint32_t);
9599 +
9600 +      if (!buf_safe (buf, 2 + size))
9601 +       {
9602 +         *error = true;
9603 +         msg (M_WARN, "write_dhcp_u32_array: buffer overflow building DHCP options");
9604 +         return;
9605 +       }
9606 +      if (size < 1 || size > 255)
9607 +       {
9608 +         *error = true;
9609 +         msg (M_WARN, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size);
9610 +         return;
9611 +       }
9612 +      buf_write_u8 (buf, type);
9613 +      buf_write_u8 (buf, size);
9614 +      for (i = 0; i < len; ++i)
9615 +       buf_write_u32 (buf, data[i]);
9616 +    }
9617 +}
9618 +
9619 +static void
9620 +write_dhcp_str (struct buffer *buf, const int type, const char *str, bool *error)
9621 +{
9622 +  const int len = strlen (str);
9623 +  if (!buf_safe (buf, 2 + len))
9624 +    {
9625 +      *error = true;
9626 +      msg (M_WARN, "write_dhcp_str: buffer overflow building DHCP options");
9627 +      return;
9628 +    }
9629 +  if (len < 1 || len > 255)
9630 +    {
9631 +      *error = true;
9632 +      msg (M_WARN, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str);
9633 +      return;
9634 +    }
9635 +  buf_write_u8 (buf, type);
9636 +  buf_write_u8 (buf, len);
9637 +  buf_write (buf, str, len);
9638 +}
9639 +
9640 +static bool
9641 +build_dhcp_options_string (struct buffer *buf, const struct tuntap_options *o)
9642 +{
9643 +  bool error = false;
9644 +  if (o->domain)
9645 +    write_dhcp_str (buf, 15, o->domain, &error);
9646 +
9647 +  if (o->netbios_scope)
9648 +    write_dhcp_str (buf, 47, o->netbios_scope, &error);
9649 +
9650 +  if (o->netbios_node_type)
9651 +    write_dhcp_u8 (buf, 46, o->netbios_node_type, &error);
9652 +
9653 +  write_dhcp_u32_array (buf, 6, (uint32_t*)o->dns, o->dns_len, &error);
9654 +  write_dhcp_u32_array (buf, 44, (uint32_t*)o->wins, o->wins_len, &error);
9655 +  write_dhcp_u32_array (buf, 42, (uint32_t*)o->ntp, o->ntp_len, &error);
9656 +  write_dhcp_u32_array (buf, 45, (uint32_t*)o->nbdd, o->nbdd_len, &error);
9657 +
9658 +  /* the MS DHCP server option 'Disable Netbios-over-TCP/IP
9659 +     is implemented as vendor option 001, value 002.
9660 +     A value of 001 means 'leave NBT alone' which is the default */
9661 +  if (o->disable_nbt)
9662 +  {
9663 +    if (!buf_safe (buf, 8))
9664 +      {
9665 +       msg (M_WARN, "build_dhcp_options_string: buffer overflow building DHCP options");
9666 +       return false;
9667 +      }
9668 +    buf_write_u8 (buf,  43);
9669 +    buf_write_u8 (buf,  6);  /* total length field */
9670 +    buf_write_u8 (buf,  0x001);
9671 +    buf_write_u8 (buf,  4);  /* length of the vendor specified field */
9672 +    buf_write_u32 (buf, 0x002);
9673 +  }
9674 +  return !error;
9675 +}
9676 +
9677 +static void
9678 +fork_dhcp_action (struct tuntap *tt)
9679 +{
9680 +  if (tt->options.dhcp_pre_release || tt->options.dhcp_renew)
9681 +    {
9682 +      struct gc_arena gc = gc_new ();
9683 +      struct buffer cmd = alloc_buf_gc (256, &gc);
9684 +      const int verb = 3;
9685 +      const int pre_sleep = 1;
9686 +  
9687 +      buf_printf (&cmd, "openvpn --verb %d --tap-sleep %d", verb, pre_sleep);
9688 +      if (tt->options.dhcp_pre_release)
9689 +       buf_printf (&cmd, " --dhcp-pre-release");
9690 +      if (tt->options.dhcp_renew)
9691 +       buf_printf (&cmd, " --dhcp-renew");
9692 +      buf_printf (&cmd, " --dhcp-internal %u", (unsigned int)tt->adapter_index);
9693 +
9694 +      fork_to_self (BSTR (&cmd));
9695 +      gc_free (&gc);
9696 +    }
9697 +}
9698 +
9699 +void
9700 +fork_register_dns_action (struct tuntap *tt)
9701 +{
9702 +  if (tt && tt->options.register_dns)
9703 +    {
9704 +      struct gc_arena gc = gc_new ();
9705 +      struct buffer cmd = alloc_buf_gc (256, &gc);
9706 +      const int verb = 3;
9707
9708 +      buf_printf (&cmd, "openvpn --verb %d --register-dns --rdns-internal", verb);
9709 +      fork_to_self (BSTR (&cmd));
9710 +      gc_free (&gc);
9711 +    }
9712 +}
9713 +
9714 +void
9715 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
9716 +{
9717 +  struct gc_arena gc = gc_new ();
9718 +  char device_path[256];
9719 +  const char *device_guid = NULL;
9720 +  DWORD len;
9721 +  bool dhcp_masq = false;
9722 +  bool dhcp_masq_post = false;
9723 +
9724 +  /*netcmd_semaphore_lock ();*/
9725 +
9726 +  msg( M_INFO, "open_tun, tt->ipv6=%d", tt->ipv6 );
9727 +
9728 +  if (tt->type == DEV_TYPE_NULL)
9729 +    {
9730 +      open_null (tt);
9731 +      gc_free (&gc);
9732 +      return;
9733 +    }
9734 +  else if (tt->type == DEV_TYPE_TAP || tt->type == DEV_TYPE_TUN)
9735 +    {
9736 +      ;
9737 +    }
9738 +  else
9739 +    {
9740 +      msg (M_FATAL|M_NOPREFIX, "Unknown virtual device type: '%s'", dev);
9741 +    }
9742 +
9743 +  /*
9744 +   * Lookup the device name in the registry, using the --dev-node high level name.
9745 +   */
9746 +  {
9747 +    const struct tap_reg *tap_reg = get_tap_reg (&gc);
9748 +    const struct panel_reg *panel_reg = get_panel_reg (&gc);
9749 +    char actual_buffer[256];
9750 +
9751 +    at_least_one_tap_win32 (tap_reg);
9752 +
9753 +    if (dev_node)
9754 +      {
9755 +        /* Get the device GUID for the device specified with --dev-node. */
9756 +        device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc);
9757 +
9758 +       if (!device_guid)
9759 +         msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node);
9760 +
9761 +        /* Open Windows TAP-Win32 adapter */
9762 +        openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s",
9763 +                         USERMODEDEVICEDIR,
9764 +                         device_guid,
9765 +                         TAPSUFFIX);
9766 +
9767 +        tt->hand = CreateFile (
9768 +                              device_path,
9769 +                              GENERIC_READ | GENERIC_WRITE,
9770 +                              0, /* was: FILE_SHARE_READ */
9771 +                              0,
9772 +                              OPEN_EXISTING,
9773 +                              FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
9774 +                              0
9775 +                              );
9776 +
9777 +        if (tt->hand == INVALID_HANDLE_VALUE)
9778 +          msg (M_ERR, "CreateFile failed on TAP device: %s", device_path);
9779 +      }
9780 +    else 
9781 +      {
9782 +        int device_number = 0;
9783 +
9784 +        /* Try opening all TAP devices until we find one available */
9785 +        while (true)
9786 +          {
9787 +            device_guid = get_unspecified_device_guid (device_number, 
9788 +                                                      actual_buffer, 
9789 +                                                      sizeof (actual_buffer),
9790 +                                                      tap_reg,
9791 +                                                      panel_reg,
9792 +                                                      &gc);
9793 +
9794 +           if (!device_guid)
9795 +             msg (M_FATAL, "All TAP-Win32 adapters on this system are currently in use.");
9796 +
9797 +            /* Open Windows TAP-Win32 adapter */
9798 +            openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s",
9799 +                                     USERMODEDEVICEDIR,
9800 +                             device_guid,
9801 +                             TAPSUFFIX);
9802 +
9803 +            tt->hand = CreateFile (
9804 +                                  device_path,
9805 +                                  GENERIC_READ | GENERIC_WRITE,
9806 +                                  0, /* was: FILE_SHARE_READ */
9807 +                                  0,
9808 +                                  OPEN_EXISTING,
9809 +                                  FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
9810 +                                  0
9811 +                                  );
9812 +
9813 +            if (tt->hand == INVALID_HANDLE_VALUE)
9814 +              msg (D_TUNTAP_INFO, "CreateFile failed on TAP device: %s", device_path);
9815 +            else
9816 +              break;
9817 +        
9818 +            device_number++;
9819 +          }
9820 +      }
9821 +
9822 +    /* translate high-level device name into a device instance
9823 +       GUID using the registry */
9824 +    tt->actual_name = string_alloc (actual_buffer, NULL);
9825 +  }
9826 +
9827 +  msg (M_INFO, "TAP-WIN32 device [%s] opened: %s", tt->actual_name, device_path);
9828 +  tt->adapter_index = get_adapter_index (device_guid);
9829 +
9830 +  /* get driver version info */
9831 +  {
9832 +    ULONG info[3];
9833 +    CLEAR (info);
9834 +    if (DeviceIoControl (tt->hand, TAP_IOCTL_GET_VERSION,
9835 +                        &info, sizeof (info),
9836 +                        &info, sizeof (info), &len, NULL))
9837 +      {
9838 +       msg (D_TUNTAP_INFO, "TAP-Win32 Driver Version %d.%d %s",
9839 +            (int) info[0],
9840 +            (int) info[1],
9841 +            (info[2] ? "(DEBUG)" : ""));
9842 +
9843 +      }
9844 +    if (!(info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR))
9845 +      msg (M_FATAL, "ERROR:  This version of " PACKAGE_NAME " requires a TAP-Win32 driver that is at least version %d.%d -- If you recently upgraded your " PACKAGE_NAME " distribution, a reboot is probably required at this point to get Windows to see the new driver.",
9846 +          TAP_WIN32_MIN_MAJOR,
9847 +          TAP_WIN32_MIN_MINOR);
9848 +
9849 +    /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy
9850 +     */
9851 +    if ( tt->type == DEV_TYPE_TUN &&
9852 +        info[0] == 9 && info[1] == 8)
9853 +      {
9854 +       msg( M_FATAL, "ERROR:  Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode.  Upgrade to Tap-Win32 9.9 (2.2.2 release or later) or use TAP mode", (int) info[0], (int) info[1] );
9855 +      }
9856 +  }
9857 +
9858 +  /* get driver MTU */
9859 +  {
9860 +    ULONG mtu;
9861 +    if (DeviceIoControl (tt->hand, TAP_IOCTL_GET_MTU,
9862 +                        &mtu, sizeof (mtu),
9863 +                        &mtu, sizeof (mtu), &len, NULL))
9864 +      {
9865 +       tt->post_open_mtu = (int) mtu;
9866 +       msg (D_MTU_INFO, "TAP-Win32 MTU=%d", (int) mtu);
9867 +      }
9868 +  }
9869 +
9870 +  /*
9871 +   * Preliminaries for setting TAP-Win32 adapter TCP/IP
9872 +   * properties via --ip-win32 dynamic or --ip-win32 adaptive.
9873 +   */
9874 +  if (tt->did_ifconfig_setup)
9875 +    {
9876 +      if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ)
9877 +       {
9878 +         /*
9879 +          * If adapter is set to non-DHCP, set to DHCP mode.
9880 +          */
9881 +         if (dhcp_status (tt->adapter_index) == DHCP_STATUS_DISABLED)
9882 +           netsh_enable_dhcp (&tt->options, tt->actual_name);
9883 +         dhcp_masq = true;
9884 +         dhcp_masq_post = true;
9885 +       }
9886 +      else if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
9887 +       {
9888 +         /*
9889 +          * If adapter is set to non-DHCP, use netsh right away.
9890 +          */
9891 +         if (dhcp_status (tt->adapter_index) != DHCP_STATUS_ENABLED)
9892 +           {
9893 +             netsh_ifconfig (&tt->options,
9894 +                             tt->actual_name,
9895 +                             tt->local,
9896 +                             tt->adapter_netmask,
9897 +                             NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS);
9898 +           }
9899 +         else
9900 +           {
9901 +             dhcp_masq = true;
9902 +           }
9903 +       }
9904 +    }
9905 +
9906 +  /* set point-to-point mode if TUN device */
9907 +
9908 +  if (tt->type == DEV_TYPE_TUN)
9909 +    {
9910 +      if (!tt->did_ifconfig_setup)
9911 +       {
9912 +         msg (M_FATAL, "ERROR: --dev tun also requires --ifconfig");
9913 +       }
9914 +
9915 +      if (tt->topology == TOP_SUBNET)
9916 +       {
9917 +         in_addr_t ep[3];
9918 +         BOOL status;
9919 +
9920 +         ep[0] = htonl (tt->local);
9921 +         ep[1] = htonl (tt->local & tt->remote_netmask);
9922 +         ep[2] = htonl (tt->remote_netmask);
9923 +
9924 +         status = DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_TUN,
9925 +                                   ep, sizeof (ep),
9926 +                                   ep, sizeof (ep), &len, NULL);
9927 +
9928 +          msg (status ? M_INFO : M_FATAL, "Set TAP-Win32 TUN subnet mode network/local/netmask = %s/%s/%s [%s]",
9929 +              print_in_addr_t (ep[1], IA_NET_ORDER, &gc),
9930 +              print_in_addr_t (ep[0], IA_NET_ORDER, &gc),
9931 +              print_in_addr_t (ep[2], IA_NET_ORDER, &gc),
9932 +              status ? "SUCCEEDED" : "FAILED");
9933 +
9934 +       } else {
9935 +
9936 +         in_addr_t ep[2];
9937 +         ep[0] = htonl (tt->local);
9938 +         ep[1] = htonl (tt->remote_netmask);
9939 +
9940 +         if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_POINT_TO_POINT,
9941 +                               ep, sizeof (ep),
9942 +                               ep, sizeof (ep), &len, NULL))
9943 +           msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun");
9944 +       }
9945 +    }
9946 +
9947 +  /* should we tell the TAP-Win32 driver to masquerade as a DHCP server as a means
9948 +     of setting the adapter address? */
9949 +  if (dhcp_masq)
9950 +    {
9951 +      uint32_t ep[4];
9952 +
9953 +      /* We will answer DHCP requests with a reply to set IP/subnet to these values */
9954 +      ep[0] = htonl (tt->local);
9955 +      ep[1] = htonl (tt->adapter_netmask);
9956 +
9957 +      /* At what IP address should the DHCP server masquerade at? */
9958 +      if (tt->type == DEV_TYPE_TUN)
9959 +       {
9960 +         if (tt->topology == TOP_SUBNET)
9961 +           {
9962 +             const in_addr_t netmask_inv = ~tt->remote_netmask;
9963 +             ep[2] = netmask_inv ? htonl ((tt->local | netmask_inv) - 1) : 0;
9964 +           }
9965 +         else
9966 +           ep[2] = htonl (tt->remote_netmask);
9967 +
9968 +         if (tt->options.dhcp_masq_custom_offset)
9969 +           msg (M_WARN, "WARNING: because you are using '--dev tun' mode, the '--ip-win32 dynamic [offset]' option is ignoring the offset parameter");
9970 +       }
9971 +      else
9972 +       {
9973 +         in_addr_t dsa; /* DHCP server addr */
9974 +
9975 +         ASSERT (tt->type == DEV_TYPE_TAP);
9976 +
9977 +         if (tt->options.dhcp_masq_offset < 0)
9978 +           dsa = (tt->local | (~tt->adapter_netmask)) + tt->options.dhcp_masq_offset;
9979 +         else
9980 +           dsa = (tt->local & tt->adapter_netmask) + tt->options.dhcp_masq_offset;
9981 +
9982 +         if (dsa == tt->local)
9983 +           msg (M_FATAL, "ERROR: There is a clash between the --ifconfig local address and the internal DHCP server address -- both are set to %s -- please use the --ip-win32 dynamic option to choose a different free address from the --ifconfig subnet for the internal DHCP server", print_in_addr_t (dsa, 0, &gc));
9984 +
9985 +         if ((tt->local & tt->adapter_netmask) != (dsa & tt->adapter_netmask))
9986 +           msg (M_FATAL, "ERROR: --tap-win32 dynamic [offset] : offset is outside of --ifconfig subnet");
9987 +
9988 +         ep[2] = htonl (dsa);
9989 +       }
9990 +
9991 +      /* lease time in seconds */
9992 +      ep[3] = (uint32_t) tt->options.dhcp_lease_time;
9993 +
9994 +      ASSERT (ep[3] > 0);
9995 +
9996 +#ifndef SIMULATE_DHCP_FAILED /* this code is disabled to simulate bad DHCP negotiation */
9997 +      if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_DHCP_MASQ,
9998 +                           ep, sizeof (ep),
9999 +                           ep, sizeof (ep), &len, NULL))
10000 +       msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a DeviceIoControl call to set TAP_IOCTL_CONFIG_DHCP_MASQ mode");
10001 +
10002 +      msg (M_INFO, "Notified TAP-Win32 driver to set a DHCP IP/netmask of %s/%s on interface %s [DHCP-serv: %s, lease-time: %d]",
10003 +          print_in_addr_t (tt->local, 0, &gc),
10004 +          print_in_addr_t (tt->adapter_netmask, 0, &gc),
10005 +          device_guid,
10006 +          print_in_addr_t (ep[2], IA_NET_ORDER, &gc),
10007 +          ep[3]
10008 +          );
10009 +
10010 +      /* user-supplied DHCP options capability */
10011 +      if (tt->options.dhcp_options)
10012 +       {
10013 +         struct buffer buf = alloc_buf (256);
10014 +         if (build_dhcp_options_string (&buf, &tt->options))
10015 +           {
10016 +             msg (D_DHCP_OPT, "DHCP option string: %s", format_hex (BPTR (&buf), BLEN (&buf), 0, &gc));
10017 +             if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_DHCP_SET_OPT,
10018 +                                   BPTR (&buf), BLEN (&buf),
10019 +                                   BPTR (&buf), BLEN (&buf), &len, NULL))
10020 +               msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a TAP_IOCTL_CONFIG_DHCP_SET_OPT DeviceIoControl call");
10021 +           }
10022 +         else
10023 +           msg (M_WARN, "DHCP option string not set due to error");
10024 +         free_buf (&buf);
10025 +       }
10026 +#endif
10027 +    }
10028 +
10029 +  /* set driver media status to 'connected' */
10030 +  {
10031 +    ULONG status = TRUE;
10032 +    if (!DeviceIoControl (tt->hand, TAP_IOCTL_SET_MEDIA_STATUS,
10033 +                         &status, sizeof (status),
10034 +                         &status, sizeof (status), &len, NULL))
10035 +      msg (M_WARN, "WARNING: The TAP-Win32 driver rejected a TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.");
10036 +  }
10037 +
10038 +  /* possible wait for adapter to come up */
10039 +  {
10040 +    int s = tt->options.tap_sleep;
10041 +    if (s > 0)
10042 +      {
10043 +       msg (M_INFO, "Sleeping for %d seconds...", s);
10044 +       openvpn_sleep (s);
10045 +      }
10046 +  }
10047 +
10048 +  /* possibly use IP Helper API to set IP address on adapter */
10049 +  {
10050 +    const DWORD index = tt->adapter_index;
10051 +    
10052 +    /* flush arp cache */
10053 +    if (index != (DWORD)~0)
10054 +      {
10055 +       DWORD status;
10056 +
10057 +       if ((status = FlushIpNetTable (index)) == NO_ERROR)
10058 +         msg (M_INFO, "Successful ARP Flush on interface [%u] %s",
10059 +              (unsigned int)index,
10060 +              device_guid);
10061 +       else
10062 +         msg (D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s",
10063 +              (unsigned int)index,
10064 +              device_guid,
10065 +              (unsigned int)status,
10066 +              strerror_win32 (status, &gc));
10067 +      }
10068 +
10069 +    /*
10070 +     * If the TAP-Win32 driver is masquerading as a DHCP server
10071 +     * make sure the TCP/IP properties for the adapter are
10072 +     * set correctly.
10073 +     */
10074 +    if (dhcp_masq_post)
10075 +      {
10076 +       /* check dhcp enable status */
10077 +       if (dhcp_status (index) == DHCP_STATUS_DISABLED)
10078 +         msg (M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'");
10079 +
10080 +       /* force an explicit DHCP lease renewal on TAP adapter? */
10081 +       if (tt->options.dhcp_pre_release)
10082 +         dhcp_release (tt);
10083 +       if (tt->options.dhcp_renew)
10084 +         dhcp_renew (tt);
10085 +      }
10086 +    else
10087 +      fork_dhcp_action (tt);
10088 +
10089 +    if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI)
10090 +      {
10091 +       DWORD status;
10092 +       const char *error_suffix = "I am having trouble using the Windows 'IP helper API' to automatically set the IP address -- consider using other --ip-win32 methods (not 'ipapi')";
10093 +
10094 +       /* couldn't get adapter index */
10095 +       if (index == (DWORD)~0)
10096 +         {
10097 +           msg (M_FATAL, "ERROR: unable to get adapter index for interface %s -- %s",
10098 +                device_guid,
10099 +                error_suffix);
10100 +         }
10101 +
10102 +       /* check dhcp enable status */
10103 +       if (dhcp_status (index) == DHCP_STATUS_DISABLED)
10104 +         msg (M_WARN, "NOTE: You have selected (explicitly or by default) '--ip-win32 ipapi', which has a better chance of working correctly if the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'");
10105 +
10106 +       /* delete previously added IP addresses which were not
10107 +          correctly deleted */
10108 +       delete_temp_addresses (index);
10109 +
10110 +       /* add a new IP address */
10111 +       if ((status = AddIPAddress (htonl(tt->local),
10112 +                                   htonl(tt->adapter_netmask),
10113 +                                   index,
10114 +                                   &tt->ipapi_context,
10115 +                                   &tt->ipapi_instance)) == NO_ERROR)
10116 +         msg (M_INFO, "Succeeded in adding a temporary IP/netmask of %s/%s to interface %s using the Win32 IP Helper API",
10117 +              print_in_addr_t (tt->local, 0, &gc),
10118 +              print_in_addr_t (tt->adapter_netmask, 0, &gc),
10119 +              device_guid
10120 +              );
10121 +       else
10122 +         msg (M_FATAL, "ERROR: AddIPAddress %s/%s failed on interface %s, index=%d, status=%u (windows error: '%s') -- %s",
10123 +              print_in_addr_t (tt->local, 0, &gc),
10124 +              print_in_addr_t (tt->adapter_netmask, 0, &gc),
10125 +              device_guid,
10126 +              (int)index,
10127 +              (unsigned int)status,
10128 +              strerror_win32 (status, &gc),
10129 +              error_suffix);
10130 +       tt->ipapi_context_defined = true;
10131 +      }
10132 +  }
10133 +  /*netcmd_semaphore_release ();*/
10134 +  gc_free (&gc);
10135 +}
10136 +
10137 +const char *
10138 +tap_win32_getinfo (const struct tuntap *tt, struct gc_arena *gc)
10139 +{
10140 +  if (tt && tt->hand != NULL)
10141 +    {
10142 +      struct buffer out = alloc_buf_gc (256, gc);
10143 +      DWORD len;
10144 +      if (DeviceIoControl (tt->hand, TAP_IOCTL_GET_INFO,
10145 +                          BSTR (&out), BCAP (&out),
10146 +                          BSTR (&out), BCAP (&out),
10147 +                          &len, NULL))
10148 +       {
10149 +         return BSTR (&out);
10150 +       }
10151 +    }
10152 +  return NULL;
10153 +}
10154 +
10155 +void
10156 +tun_show_debug (struct tuntap *tt)
10157 +{
10158 +  if (tt && tt->hand != NULL)
10159 +    {
10160 +      struct buffer out = alloc_buf (1024);
10161 +      DWORD len;
10162 +      while (DeviceIoControl (tt->hand, TAP_IOCTL_GET_LOG_LINE,
10163 +                             BSTR (&out), BCAP (&out),
10164 +                             BSTR (&out), BCAP (&out),
10165 +                             &len, NULL))
10166 +       {
10167 +         msg (D_TAP_WIN32_DEBUG, "TAP-Win32: %s", BSTR (&out));
10168 +       }
10169 +      free_buf (&out);
10170 +    }
10171 +}
10172 +
10173 +void
10174 +close_tun (struct tuntap *tt)
10175 +{
10176 +  struct gc_arena gc = gc_new ();
10177 +
10178 +  if (tt)
10179 +    {
10180 +      if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
10181 +        {
10182 +         struct argv argv;
10183 +         argv_init (&argv);
10184 +
10185 +         /* remove route pointing to interface */
10186 +         delete_route_connected_v6_net(tt, NULL);
10187 +
10188 +         /* netsh interface ipv6 delete address \"%s\" %s */
10189 +         const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
10190 +         argv_printf (&argv,
10191 +                   "%s%sc interface ipv6 delete address %s %s",
10192 +                    get_win_sys_path(),
10193 +                    NETSH_PATH_SUFFIX,
10194 +                    tt->actual_name,
10195 +                    ifconfig_ipv6_local );
10196 +
10197 +         netsh_command (&argv, 1);
10198 +          argv_reset (&argv);
10199 +       }
10200 +#if 1
10201 +      if (tt->ipapi_context_defined)
10202 +       {
10203 +         DWORD status;
10204 +         if ((status = DeleteIPAddress (tt->ipapi_context)) != NO_ERROR)
10205 +           {
10206 +             msg (M_WARN, "Warning: DeleteIPAddress[%u] failed on TAP-Win32 adapter, status=%u : %s",
10207 +                  (unsigned int)tt->ipapi_context,
10208 +                  (unsigned int)status,
10209 +                  strerror_win32 (status, &gc));
10210 +           }
10211 +       }
10212 +#endif
10213 +
10214 +      if (tt->options.dhcp_release)
10215 +       dhcp_release (tt);
10216 +
10217 +      if (tt->hand != NULL)
10218 +       {
10219 +         dmsg (D_WIN32_IO_LOW, "Attempting CancelIO on TAP-Win32 adapter");
10220 +         if (!CancelIo (tt->hand))
10221 +           msg (M_WARN | M_ERRNO, "Warning: CancelIO failed on TAP-Win32 adapter");
10222 +       }
10223 +
10224 +      dmsg (D_WIN32_IO_LOW, "Attempting close of overlapped read event on TAP-Win32 adapter");
10225 +      overlapped_io_close (&tt->reads);
10226 +
10227 +      dmsg (D_WIN32_IO_LOW, "Attempting close of overlapped write event on TAP-Win32 adapter");
10228 +      overlapped_io_close (&tt->writes);
10229 +
10230 +      if (tt->hand != NULL)
10231 +       {
10232 +         dmsg (D_WIN32_IO_LOW, "Attempting CloseHandle on TAP-Win32 adapter");
10233 +         if (!CloseHandle (tt->hand))
10234 +           msg (M_WARN | M_ERRNO, "Warning: CloseHandle failed on TAP-Win32 adapter");
10235 +       }
10236 +
10237 +      if (tt->actual_name)
10238 +       free (tt->actual_name);
10239 +
10240 +      clear_tuntap (tt);
10241 +      free (tt);
10242 +    }
10243 +  gc_free (&gc);
10244 +}
10245 +
10246 +/*
10247 + * Convert --ip-win32 constants between index and ascii form.
10248 + */
10249 +
10250 +struct ipset_names {
10251 +  const char *short_form;
10252 +};
10253 +
10254 +/* Indexed by IPW32_SET_x */
10255 +static const struct ipset_names ipset_names[] = {
10256 +  {"manual"},
10257 +  {"netsh"},
10258 +  {"ipapi"},
10259 +  {"dynamic"},
10260 +  {"adaptive"}
10261 +};
10262 +
10263 +int
10264 +ascii2ipset (const char* name)
10265 +{
10266 +  int i;
10267 +  ASSERT (IPW32_SET_N == SIZE (ipset_names));
10268 +  for (i = 0; i < IPW32_SET_N; ++i)
10269 +    if (!strcmp (name, ipset_names[i].short_form))
10270 +      return i;
10271 +  return -1;
10272 +}
10273 +
10274 +const char *
10275 +ipset2ascii (int index)
10276 +{
10277 +  ASSERT (IPW32_SET_N == SIZE (ipset_names));
10278 +  if (index < 0 || index >= IPW32_SET_N)
10279 +    return "[unknown --ip-win32 type]";
10280 +  else
10281 +    return ipset_names[index].short_form;
10282 +}
10283 +
10284 +const char *
10285 +ipset2ascii_all (struct gc_arena *gc)
10286 +{
10287 +  struct buffer out = alloc_buf_gc (256, gc);
10288 +  int i;
10289 +
10290 +  ASSERT (IPW32_SET_N == SIZE (ipset_names));
10291 +  for (i = 0; i < IPW32_SET_N; ++i)
10292 +    {
10293 +      if (i)
10294 +       buf_printf(&out, " ");
10295 +      buf_printf(&out, "[%s]", ipset2ascii(i));
10296 +    }
10297 +  return BSTR (&out);
10298 +}
10299 +
10300 +#else /* generic */
10301 +
10302 +void
10303 +open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
10304 +{
10305 +  open_tun_generic (dev, dev_type, dev_node, false, true, tt);
10306 +}
10307 +
10308 +void
10309 +close_tun (struct tuntap* tt)
10310 +{
10311 +  if (tt)
10312 +    {
10313 +      close_tun_generic (tt);
10314 +      free (tt);
10315 +    }
10316 +}
10317 +
10318 +int
10319 +write_tun (struct tuntap* tt, uint8_t *buf, int len)
10320 +{
10321 +  return write (tt->fd, buf, len);
10322 +}
10323 +
10324 +int
10325 +read_tun (struct tuntap* tt, uint8_t *buf, int len)
10326 +{
10327 +  return read (tt->fd, buf, len);
10328 +}
10329 +
10330 +#endif
10331 diff -durN openvpn-2.2.2.orig/tun.h openvpn-2.2.2/tun.h
10332 --- openvpn-2.2.2.orig/tun.h    2011-12-13 17:58:56.000000000 +0100
10333 +++ openvpn-2.2.2/tun.h 2012-06-01 10:40:28.000000000 +0200
10334 @@ -130,6 +130,7 @@
10335    int topology; /* one of the TOP_x values */
10336  
10337    bool did_ifconfig_setup;
10338 +  bool did_ifconfig_ipv6_setup;
10339    bool did_ifconfig;
10340  
10341    bool ipv6;
10342 @@ -146,6 +147,10 @@
10343    in_addr_t remote_netmask;
10344    in_addr_t broadcast;
10345  
10346 +  struct in6_addr local_ipv6;
10347 +  struct in6_addr remote_ipv6;
10348 +  int netbits_ipv6;
10349 +
10350  #ifdef WIN32
10351    HANDLE hand;
10352    struct overlapped_io reads;
10353 @@ -197,7 +202,7 @@
10354  void clear_tuntap (struct tuntap *tuntap);
10355  
10356  void open_tun (const char *dev, const char *dev_type, const char *dev_node,
10357 -              bool ipv6, struct tuntap *tt);
10358 +              struct tuntap *tt);
10359  
10360  void close_tun (struct tuntap *tt);
10361  
10362 @@ -206,7 +211,7 @@
10363  int read_tun (struct tuntap* tt, uint8_t *buf, int len);
10364  
10365  void tuncfg (const char *dev, const char *dev_type, const char *dev_node,
10366 -            bool ipv6, int persist_mode, const char *username,
10367 +            int persist_mode, const char *username,
10368              const char *groupname, const struct tuntap_options *options);
10369  
10370  const char *guess_tuntap_dev (const char *dev,
10371 @@ -219,6 +224,8 @@
10372                          int topology,          /* one of the TOP_x values */
10373                          const char *ifconfig_local_parm,          /* --ifconfig parm 1 */
10374                          const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
10375 +                        const char *ifconfig_ipv6_local_parm,     /* --ifconfig parm 1 / IPv6 */
10376 +                        const char *ifconfig_ipv6_remote_parm,    /* --ifconfig parm 2 / IPv6 */
10377                          in_addr_t local_public,
10378                          in_addr_t remote_public,
10379                          const bool strict_warn,
10380 diff -durN openvpn-2.2.2.orig/win32.c openvpn-2.2.2/win32.c
10381 --- openvpn-2.2.2.orig/win32.c  2011-12-13 17:58:56.000000000 +0100
10382 +++ openvpn-2.2.2/win32.c       2012-06-01 10:40:28.000000000 +0200
10383 @@ -874,16 +874,21 @@
10384  static char *
10385  env_block (const struct env_set *es)
10386  {
10387 +  char * force_path = "PATH=C:\\Windows\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem";
10388 +
10389    if (es)
10390      {
10391        struct env_item *e;
10392        char *ret;
10393        char *p;
10394        size_t nchars = 1;
10395 +      bool path_seen = false;
10396        
10397        for (e = es->list; e != NULL; e = e->next)
10398         nchars += strlen (e->string) + 1;
10399  
10400 +      nchars += strlen(force_path)+1;
10401 +
10402        ret = (char *) malloc (nchars);
10403        check_malloc_return (ret);
10404  
10405 @@ -895,7 +900,18 @@
10406               strcpy (p, e->string);
10407               p += strlen (e->string) + 1;
10408             }
10409 +         if ( strncmp(e->string, "PATH=", 5 ) == 0 )
10410 +           path_seen = true;
10411 +       }
10412 +
10413 +      /* make sure PATH is set */
10414 +      if ( !path_seen )
10415 +       {
10416 +         msg( M_INFO, "env_block: add %s", force_path );
10417 +         strcpy( p, force_path );
10418 +         p += strlen(force_path) + 1;
10419         }
10420 +
10421        *p = '\0';
10422        return ret;
10423      }
10424 diff -durN openvpn-2.2.2.orig/win32.h openvpn-2.2.2/win32.h
10425 --- openvpn-2.2.2.orig/win32.h  2011-12-13 17:58:56.000000000 +0100
10426 +++ openvpn-2.2.2/win32.h       2012-06-01 10:40:28.000000000 +0200
10427 @@ -269,6 +269,8 @@
10428  
10429  /* call self in a subprocess */
10430  void fork_to_self (const char *cmdline);
10431 +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
10432 +int inet_pton(int af, const char *src, void *st);
10433  
10434  /* Find temporary directory */
10435  const char *win_get_tempdir();