diff --git a/vpnc-script-win.js b/vpnc-script-win.js index a3a0974..f60b74d 100644 --- a/vpnc-script-win.js +++ b/vpnc-script-win.js @@ -1,25 +1,81 @@ +// // vpnc-script-win.js // // Sets up the Network interface and the routes // needed by vpnc. +// // -------------------------------------------------------------- -// Utilities +// Initial setup // -------------------------------------------------------------- +var internal_ip4_netmask = "255.255.255.0"; + +var accumulatedExitCode = 0; + +var ws = WScript.CreateObject("WScript.Shell"); +var env = ws.Environment("Process"); +var comspec = ws.ExpandEnvironmentStrings("%comspec%"); + +if (env("LOG2FILE")) { + var fs = WScript.CreateObject("Scripting.FileSystemObject"); + var tmpdir = fs.GetSpecialFolder(2)+"\\"; + var log = fs.OpenTextFile(tmpdir + "vpnc.log", 8, true); +} + +// How to add the default internal route +// -1 - Do not touch default route (but do other necessary route setups) +// 0 - As interface gateway when setting properties +// 1 - As a 0.0.0.0/0 route with a lower metric than the default route +// 2 - As 0.0.0.0/1 + 128.0.0.0/1 routes (override the default route cleanly) +if (env("REDIRECT_GATEWAY_METHOD")) { + var REDIRECT_GATEWAY_METHOD = env("REDIRECT_GATEWAY_METHOD"); +} else { + var REDIRECT_GATEWAY_METHOD = 0; +} + +// -------------------------------------------------------------- +// Utilities +// -------------------------------------------------------------- function echo(msg) { - WScript.echo(msg); + // TODO: prepend UTC? timestamp to every message + if (env("LOG2FILE")) { + log.WriteLine(msg); + } else { + WScript.echo(msg); + } +} + +function echoMultiLine(msg) +{ + if (env("LOG2FILE")) { + log.Write(msg); + } else { + WScript.echo(msg); + } } -function run(cmd) +function exec(cmd) { - return (ws.Exec(cmd).StdOut.ReadAll()); + echo("<<-- [EXEC] " + cmd); + var oExec = ws.Exec(comspec + " /C \"" + cmd + "\" 2>&1"); + oExec.StdIn.Close(); + + var s = oExec.StdOut.ReadAll(); + echoMultiLine(s); + + var status = oExec.Status; + var exitCode = oExec.ExitCode; + echo("-->> (exitCode: " + exitCode + ")"); + accumulatedExitCode += exitCode; + + return s; } function getDefaultGateway() { - if (run("route print").match(/0\.0\.0\.0 *(0|128)\.0\.0\.0 *([0-9\.]*)/)) { + if (exec("route print").match(/0\.0\.0\.0 *(0|128)\.0\.0\.0 *([0-9\.]*)/)) { return (RegExp.$2); } return (""); @@ -30,28 +86,17 @@ function waitForInterface() { for (var i = 0; i < 5; i++) { echo("Waiting for interface to come up..."); WScript.Sleep(2000); - if (run("route print").match(if_route)) { + if (exec("route print").match(if_route)) { return true; } } return false; } + // -------------------------------------------------------------- // Script starts here // -------------------------------------------------------------- - -var internal_ip4_netmask = "255.255.255.0" - -var ws = WScript.CreateObject("WScript.Shell"); -var env = ws.Environment("Process"); - -// How to add the default internal route -// 0 - As interface gateway when setting properties -// 1 - As a 0.0.0.0/0 route with a lower metric than the default route -// 2 - As 0.0.0.0/1 + 128.0.0.0/1 routes (override the default route cleanly) -var REDIRECT_GATEWAY_METHOD = 0; - switch (env("reason")) { case "pre-init": break; @@ -68,64 +113,61 @@ case "connect": ); var internal_gw = internal_gw_array.join("."); + echo("Default Gateway:" + gw) echo("VPN Gateway: " + env("VPNGATEWAY")); echo("Internal Address: " + env("INTERNAL_IP4_ADDRESS")); echo("Internal Netmask: " + env("INTERNAL_IP4_NETMASK")); echo("Internal Gateway: " + internal_gw); - echo("Interface: \"" + env("TUNDEV") + "\""); + echo("Interface idx: " + env("TUNIDX") + " (\"" + env("TUNDEV") + "\")"); + // Add direct route for the VPN gateway to avoid routing loops + exec("route add " + env("VPNGATEWAY") + " mask 255.255.255.255 " + gw); + if (env("INTERNAL_IP4_MTU")) { - echo("MTU: " + env("INTERNAL_IP4_MTU")); - run("netsh interface ipv4 set subinterface \"" + env("TUNDEV") + - "\" mtu=" + env("INTERNAL_IP4_MTU") + " store=active"); - if (env("INTERNAL_IP6_ADDRESS")) { - run("netsh interface ipv6 set subinterface \"" + env("TUNDEV") + - "\" mtu=" + env("INTERNAL_IP4_MTU") + " store=active"); - } + echo("MTU: " + env("INTERNAL_IP4_MTU")); + exec("netsh interface ipv4 set subinterface " + env("TUNIDX") + " mtu=" + env("INTERNAL_IP4_MTU") + " store=active"); + if (env("INTERNAL_IP6_ADDRESS")) { + exec("netsh interface ipv6 set subinterface " + env("TUNIDX") + " mtu=" + env("INTERNAL_IP4_MTU") + " store=active"); + } + } + + // Set the default domain + if (env("CISCO_DEF_DOMAIN")) { + exec("wmic path Win32_NetworkAdapterConfiguration where InterfaceIndex=" + env("TUNIDX") + " call SetDNSDomain " + env("CISCO_DEF_DOMAIN")); } - echo("Configuring \"" + env("TUNDEV") + "\" interface for Legacy IP..."); + echo("Configuring " + env("TUNIDX") + " interface for Legacy IP..."); if (!env("CISCO_SPLIT_INC") && REDIRECT_GATEWAY_METHOD != 2) { // Interface metric must be set to 1 in order to add a route with metric 1 since Windows Vista - run("netsh interface ip set interface \"" + env("TUNDEV") + "\" metric=1"); + exec("netsh interface ip set interface " + env("TUNIDX") + " metric=1"); } - if (env("CISCO_SPLIT_INC") || REDIRECT_GATEWAY_METHOD > 0) { - run("netsh interface ip set address \"" + env("TUNDEV") + "\" static " + - env("INTERNAL_IP4_ADDRESS") + " " + env("INTERNAL_IP4_NETMASK")); + if (env("CISCO_SPLIT_INC") || REDIRECT_GATEWAY_METHOD != 0) { + exec("netsh interface ip set address " + env("TUNIDX") + " static " + env("INTERNAL_IP4_ADDRESS") + " " + env("INTERNAL_IP4_NETMASK")); } else { // The default route will be added automatically - run("netsh interface ip set address \"" + env("TUNDEV") + "\" static " + - env("INTERNAL_IP4_ADDRESS") + " " + env("INTERNAL_IP4_NETMASK") + " " + internal_gw + " 1"); + exec("netsh interface ip set address " + env("TUNIDX") + " static " + env("INTERNAL_IP4_ADDRESS") + " " + env("INTERNAL_IP4_NETMASK") + " " + internal_gw + " 1"); } - // Add direct route for the VPN gateway to avoid routing loops - run("route add " + env("VPNGATEWAY") + - " mask 255.255.255.255 " + gw); - - if (env("INTERNAL_IP4_NBNS")) { + if (env("INTERNAL_IP4_NBNS")) { var wins = env("INTERNAL_IP4_NBNS").split(/ /); for (var i = 0; i < wins.length; i++) { - run("netsh interface ip add wins \"" + - env("TUNDEV") + "\" " + wins[i] - + " index=" + (i+1)); + exec("netsh interface ip add wins " + env("TUNIDX") + " " + wins[i] + " index=" + (i+1)); } } - if (env("INTERNAL_IP4_DNS")) { + if (env("INTERNAL_IP4_DNS")) { var dns = env("INTERNAL_IP4_DNS").split(/ /); for (var i = 0; i < dns.length; i++) { - run("netsh interface ip add dns \"" + - env("TUNDEV") + "\" " + dns[i] - + " index=" + (i+1)); + exec("netsh interface ip add dns " + env("TUNIDX") + " " + dns[i] + " index=" + (i+1)); } } echo("done."); // Add internal network routes - echo("Configuring Legacy IP networks:"); - if (env("CISCO_SPLIT_INC")) { + echo("Configuring Legacy IP networks:"); + if (env("CISCO_SPLIT_INC")) { // Waiting for the interface to be configured before to add routes if (!waitForInterface()) { echo("Interface does not seem to be up."); @@ -134,10 +176,8 @@ case "connect": for (var i = 0 ; i < parseInt(env("CISCO_SPLIT_INC")); i++) { var network = env("CISCO_SPLIT_INC_" + i + "_ADDR"); var netmask = env("CISCO_SPLIT_INC_" + i + "_MASK"); - var netmasklen = env("CISCO_SPLIT_INC_" + i + - "_MASKLEN"); - run("route add " + network + " mask " + netmask + - " " + internal_gw); + var netmasklen = env("CISCO_SPLIT_INC_" + i + "_MASKLEN"); + exec("route add " + network + " mask " + netmask + " " + internal_gw); } } else if (REDIRECT_GATEWAY_METHOD > 0) { // Waiting for the interface to be configured before to add routes @@ -146,53 +186,86 @@ case "connect": } if (REDIRECT_GATEWAY_METHOD == 1) { - run("route add 0.0.0.0 mask 0.0.0.0 " + internal_gw + " metric 1"); + exec("route add 0.0.0.0 mask 0.0.0.0 " + internal_gw + " metric 1"); } else { - run("route add 0.0.0.0 mask 128.0.0.0 " + internal_gw); - run("route add 128.0.0.0 mask 128.0.0.0 " + internal_gw); + exec("route add 0.0.0.0 mask 128.0.0.0 " + internal_gw); + exec("route add 128.0.0.0 mask 128.0.0.0 " + internal_gw); } } echo("Route configuration done."); - if (env("INTERNAL_IP6_ADDRESS")) { - echo("Configuring \"" + env("TUNDEV") + "\" interface for IPv6..."); - - run("netsh interface ipv6 set address \"" + env("TUNDEV") + "\" " + - env("INTERNAL_IP6_ADDRESS") + " store=active"); - + if (env("INTERNAL_IP6_ADDRESS")) { + echo("Configuring " + env("TUNIDX") + " interface for IPv6..."); + exec("netsh interface ipv6 set address " + env("TUNIDX") + " " + env("INTERNAL_IP6_ADDRESS") + " store=active"); echo("done."); // Add internal network routes - echo("Configuring IPv6 networks:"); - if (env("INTERNAL_IP6_NETMASK") && !env("INTERNAL_IP6_NETMASK").match("/128$")) { - run("netsh interface ipv6 add route " + env("INTERNAL_IP6_NETMASK") + - " \"" + env("TUNDEV") + "\" fe80::8 store=active") + echo("Configuring IPv6 networks:"); + if (env("INTERNAL_IP6_NETMASK") && !env("INTERNAL_IP6_NETMASK").match("/128$")) { + exec("netsh interface ipv6 add route " + env("INTERNAL_IP6_NETMASK") + " " + env("TUNIDX") + " fe80::8 store=active"); } - if (env("CISCO_IPV6_SPLIT_INC")) { + if (env("CISCO_IPV6_SPLIT_INC")) { for (var i = 0 ; i < parseInt(env("CISCO_IPV6_SPLIT_INC")); i++) { var network = env("CISCO_IPV6_SPLIT_INC_" + i + "_ADDR"); - var netmasklen = env("CISCO_SPLIT_INC_" + i + - "_MASKLEN"); - run("netsh interface ipv6 add route " + network + "/" + - netmasklen + " \"" + env("TUNDEV") + "\" fe80::8 store=active") + var netmasklen = env("CISCO_SPLIT_INC_" + i + "_MASKLEN"); + exec("netsh interface ipv6 add route " + network + "/" + netmasklen + " " + env("TUNIDX") + " fe80::8 store=active"); } } else { echo("Setting default IPv6 route through VPN."); - run("netsh interface ipv6 add route 2000::/3 \"" + env("TUNDEV") + - "\" fe80::8 store=active"); + exec("netsh interface ipv6 add route 2000::/3 " + env("TUNIDX") + " fe80::8 store=active"); } echo("IPv6 route configuration done."); } if (env("CISCO_BANNER")) { - echo("--------------------------------------------------"); + echo("--------------------- BANNER ---------------------"); echo(env("CISCO_BANNER")); - echo("--------------------------------------------------"); + echo("------------------- BANNER end -------------------"); } break; case "disconnect": - // Delete direct route for the VPN gateway to avoid - run("route delete " + env("VPNGATEWAY") + " mask 255.255.255.255"); + var gw = getDefaultGateway(); + + echo("Default Gateway: " + gw) + echo("Interface idx: " + env("TUNIDX") + " (\"" + env("TUNDEV") + "\")"); + + // Delete direct route for the VPN gateway + echo("Deleting Direct Route for VPN Gateway"); + exec("route delete " + env("VPNGATEWAY") + " mask 255.255.255.255"); + + // Restore direct route + echo("Restoring Direct Route"); + exec("route delete 0.0.0.0 mask 0.0.0.0 "); + exec("route add 0.0.0.0 mask 0.0.0.0 " + gw); + + // ReSet Tunnel Adapter IP = nothing + echo("Resetting Tunnel Adapter IP"); + exec("netsh interface ip set address " + env("TUNIDX") + " source=static 1.0.0.0 255.255.255.255"); + exec("netsh interface ip delete address " + env("TUNIDX") + " 1.0.0.0"); + + // Take Down IPv4 Split Tunnel Server-side Network Routes + if (env("CISCO_SPLIT_INC")) { + echo(">Removing IPv4 Split Tunnel INC Server-side Network Routes:"); + for (var i = 0 ; i < parseInt(env("CISCO_SPLIT_INC")); i++) { + var network = env("CISCO_SPLIT_INC_" + i + "_ADDR"); + var netmask = env("CISCO_SPLIT_INC_" + i + "_MASK"); + exec("route delete " + network); + } + } + + // Take Down IPv4 Split Tunnel Client-side Network Routes + if (env("CISCO_SPLIT_LCL")) { + echo("Removing IPv4 Split Tunnel Local Client-side Network Routes:"); + for (var i = 0 ; i < parseInt(env("CISCO_SPLIT_LCL")); i++) { + var network = env("CISCO_SPLIT_LCL_" + i + "_ADDR"); + var netmask = env("CISCO_SPLIT_LCL_" + i + "_MASK"); + exec("route delete " + network); + } + } } +if (env("LOG2FILE")) { + log.Close(); +} +WScript.Quit(accumulatedExitCode);