Example #1
0
        // Apply some fixes
        public void Normalize()
        {
            // TOOPTIMIZE: Currently Eddie don't work well with verb>3
            AppendDirective("verb", "3", "");

            // Eddie have it's own Lock DNS (based on WFP, same as block-outside-dns)
            if (ExistsDirective("block-outside-dns"))
            {
                RemoveDirective("block-outside-dns");
            }

            // explicit-exit-notify works only with udp
            if (GetOneDirectiveText("proto").ToLowerInvariant().StartsWith("udp", StringComparison.InvariantCulture) == false)
            {
                RemoveDirective("explicit-exit-notify");
            }

            // OpenVPN < 2.4 allows 100 route directives max by default.
            // Since Eddie can't know here how many routes are pulled from an OpenVPN server, it uses some tolerance. In any case manual setting is possible.

            if (Software.GetTool("openvpn").VersionUnder("2.4"))            // max-routes is deprecated in 2.4
            {
                if (ExistsDirective("max-routes") == false)                 // Only if not manually specified
                {
                    if (ExistsDirective("route"))
                    {
                        List <Directive> routes = Directives["route"];
                        if ((routes != null) && (routes.Count > 50))
                        {
                            AppendDirective("max-routes", (routes.Count + 100).ToString(), "Automatic");
                        }
                    }
                }
            }
        }
Example #2
0
        public virtual string GenerateEnvironmentReport()
        {
            string t = "";

            t += "Eddie version: " + Constants.VersionDesc + "\n";
            t += "Eddie OS build: " + Platform.Instance.GetSystemCode() + "\n";
            t += "OS type: " + Platform.Instance.GetCode() + "\n";
            t += "OS name: " + Platform.Instance.GetName() + "\n";
            t += "OS description: " + Platform.Instance.VersionDescription() + "\n";
            t += "Mono /.Net Framework: " + Platform.Instance.GetMonoVersion() + "\n";

            t += "OpenVPN driver: " + Software.OpenVpnDriver + "\n";
            t += "OpenVPN: " + Software.GetTool("openvpn").Version + " (" + Software.GetTool("openvpn").Path + ")\n";
            t += "SSH: " + Software.GetTool("ssh").Version + " (" + Software.GetTool("ssh").Path + ")\n";
            t += "SSL: " + Software.GetTool("ssl").Version + " (" + Software.GetTool("ssl").Path + ")\n";
            t += "curl: " + Software.GetTool("curl").Version + " (" + Software.GetTool("curl").Path + ")\n";

            t += "Profile path: " + Engine.Instance.Storage.GetProfilePath() + "\n";
            t += "Data path: " + Storage.DataPath + "\n";
            t += "Application path: " + Platform.Instance.GetApplicationPath() + "\n";
            t += "Executable path: " + Platform.Instance.GetExecutablePath() + "\n";
            t += "Command line arguments (" + CommandLine.SystemEnvironment.Params.Count.ToString() + "): " + CommandLine.SystemEnvironment.GetFull() + "\n";

            return(t);
        }
Example #3
0
        public string Get()
        {
            string result = "";

            DateTime now = DateTime.UtcNow;

            result += "# " + Engine.Instance.GenerateFileHeader() + " - " + now.ToLongDateString() + " " + now.ToLongTimeString() + " UTC\n";

            // Obtain directive key list
            List <string> directives = new List <string>();

            foreach (KeyValuePair <string, List <Directive> > kp in Directives)
            {
                directives.Add(kp.Key);
            }

            // Sorting
            directives.Sort(CompareDirectiveOrder);

            foreach (string directiveKey in directives)
            {
                List <Directive> directivesKey = Directives[directiveKey];
                foreach (Directive value in directivesKey)
                {
                    if (directiveKey.StartsWithInv("<"))
                    {
                        result += directiveKey + "\n" + value.Text.Trim() + "\n" + directiveKey.Replace("<", "</");
                    }
                    else
                    {
                        if (value.Text.Trim() != "")
                        {
                            result += directiveKey + " " + value.Text.Trim();
                        }
                        else
                        {
                            result += directiveKey;
                        }
                    }

                    if ((Software.GetTool("openvpn") as Tools.OpenVPN).IsAirSpecialBuild() == false) // Known OpenVPN 3.3 bug: don't trim # comments
                    {
                        if (value.Comment != "")
                        {
                            result += " # " + value.Comment;
                        }
                    }
                    result += "\n";
                }
            }

            return(result);
        }
Example #4
0
        public void Environment()
        {
            Add("Eddie version", Constants.VersionShow);
            Add("Eddie OS build", Platform.Instance.GetSystemCode());
            Add("Eddie architecture", Platform.Instance.GetArchitecture());
            Add("OS type", Platform.Instance.GetCode());
            Add("OS name", Platform.Instance.GetName());
            Add("OS version", Platform.Instance.GetVersion());
            Add("OS architecture", Platform.Instance.GetOsArchitecture());
            Add("Mono /.Net Framework", Platform.Instance.GetNetFrameworkVersion());

            Add("TUN driver", Software.TunDriver);
            Add("OpenVPN", Software.GetTool("openvpn").Version + " (" + Software.GetTool("openvpn").Path + ")");
            Add("Hummingbird", Software.GetTool("hummingbird").Version + " (" + Software.GetTool("hummingbird").Path + ")");
            Add("SSH", Software.GetTool("ssh").Version + " (" + Software.GetTool("ssh").Path + ")");
            Add("SSL", Software.GetTool("ssl").Version + " (" + Software.GetTool("ssl").Path + ")");
            if (Platform.Instance.FetchUrlInternal() == false)
            {
                Add("curl", Software.GetTool("curl").Version + " (" + Software.GetTool("curl").Path + ")");
            }

            Add("Profile path", Engine.Instance.GetProfilePath());
            Add("Data path", Engine.Instance.GetDataPath());
            Add("Application path", Platform.Instance.GetApplicationPath());
            Add("Executable path", Platform.Instance.GetExecutablePath());
            Add("Command line arguments", "(" + Engine.Instance.StartCommandLine.Params.Count.ToString() + " args) " + Engine.Instance.StartCommandLine.GetFull());

            {
                string nl = LanguageManager.GetText("No");
                if (Engine.Instance.NetworkLockManager.IsActive())
                {
                    nl = LanguageManager.GetText("Yes") + ", " + Engine.Instance.NetworkLockManager.GetActive().GetName();
                }
                Add("Network Lock Active", nl);
            }

            {
                string cn = LanguageManager.GetText("No");
                if (Engine.Instance.IsConnected())
                {
                    cn = LanguageManager.GetText("Yes") + ", " + Engine.Instance.Stats.Get("ServerName").Text;
                }
                Add("Connected to VPN", cn);
            }

            Add("Detected DNS", Platform.Instance.DetectDNS().ToString());
            //Add("Detected Exit", Engine.Instance.DiscoverExit().ToString());
        }
Example #5
0
        public void Environment()
        {
            Add("Eddie version", Common.Constants.VersionDesc);
            Add("Eddie OS build", Platform.Instance.GetSystemCode());
            Add("Eddie architecture", Platform.Instance.GetArchitecture());
            Add("OS type", Platform.Instance.GetCode());
            Add("OS name", Platform.Instance.GetName());
            Add("OS version", Platform.Instance.GetVersion());
            Add("OS architecture", Platform.Instance.GetOsArchitecture());
            Add("Mono /.Net Framework", Platform.Instance.GetNetFrameworkVersion());

            Add("OpenVPN driver", Software.OpenVpnDriver);
            Add("OpenVPN", Software.GetTool("openvpn").Version + " (" + Software.GetTool("openvpn").Path + ")");
            Add("SSH", Software.GetTool("ssh").Version + " (" + Software.GetTool("ssh").Path + ")");
            Add("SSL", Software.GetTool("ssl").Version + " (" + Software.GetTool("ssl").Path + ")");
            Add("curl", Software.GetTool("curl").Version + " (" + Software.GetTool("curl").Path + ")");

            Add("Profile path", Engine.Instance.Storage.GetProfilePath());
            Add("Data path", Engine.Instance.Storage.GetDataPath());
            Add("Application path", Platform.Instance.GetApplicationPath());
            Add("Executable path", Platform.Instance.GetExecutablePath());
            Add("Command line arguments", "(" + Common.CommandLine.SystemEnvironment.Params.Count.ToString() + " args) " + Common.CommandLine.SystemEnvironment.GetFull());

            {
                string nl = Messages.No;
                if (Engine.Instance.NetworkLockManager.IsActive())
                {
                    nl = Messages.Yes + ", " + Engine.Instance.NetworkLockManager.GetActive().GetName();
                }
                Add("Network Lock Active", nl);
            }

            {
                string cn = Messages.No;
                if (Engine.Instance.IsConnected())
                {
                    cn = Messages.Yes + ", " + Engine.Instance.Stats.Get("ServerName").Text;
                }
                Add("Connected to VPN", cn);
            }

            Add("Detected DNS", Platform.Instance.DetectDNS().ToString());
            //Add("Detected Exit", Engine.Instance.DiscoverExit().ToString());
        }
Example #6
0
        public ConnectionActive BuildConnectionActive(bool preview)
        {
            // If preview, no physical additional files are created.

            ConnectionActive connectionActive = new ConnectionActive();

            Storage s = Engine.Instance.Storage;

            connectionActive.OpenVpnProfileStartup = new OvpnBuilder();
            OvpnBuilder ovpn = connectionActive.OpenVpnProfileStartup;

            ovpn.AppendDirective("setenv", "IV_GUI_VER " + Constants.Name + Constants.VersionDesc, "Client level");

            if (s.GetBool("openvpn.skip_defaults") == false)
            {
                ovpn.AppendDirectives(Engine.Instance.Storage.Get("openvpn.directives"), "Client level");
                string directivesPath = Engine.Instance.Storage.Get("openvpn.directives.path");
                if (directivesPath.Trim() != "")
                {
                    try
                    {
                        if (Platform.Instance.FileExists(directivesPath))
                        {
                            string text = Platform.Instance.FileContentsReadText(directivesPath);
                            ovpn.AppendDirectives(text, "Client level");
                        }
                        else
                        {
                            Engine.Instance.Logs.Log(LogType.Warning, LanguageManager.GetText("FileNotFound", directivesPath));
                        }
                    }
                    catch (Exception ex)
                    {
                        Engine.Instance.Logs.Log(LogType.Warning, LanguageManager.GetText("FileErrorRead", directivesPath, ex.Message));
                    }
                }
                Provider.OnBuildOvpnDefaults(ovpn);

                ovpn.AppendDirectives(OvpnDirectives, "Server level");

                if (Path != "")
                {
                    if (Platform.Instance.FileExists(Path))
                    {
                        string text = Platform.Instance.FileContentsReadText(Path);
                        ovpn.AppendDirectives(text, "Config file");

                        string dirPath = Platform.Instance.FileGetDirectoryPath(Path);
                        ovpn.NormalizeRelativePath(dirPath);
                    }
                }
            }

            if (s.Get("openvpn.dev_node") != "")
            {
                ovpn.AppendDirective("dev-node", s.Get("openvpn.dev_node"), "");
            }

            if (s.Get("network.entry.iface") != "")
            {
                ovpn.AppendDirective("local", s.Get("network.entry.iface"), "");
                ovpn.RemoveDirective("nobind");
            }
            else
            {
                ovpn.RemoveDirective("local");
                ovpn.AppendDirective("nobind", "", "");
            }

            int rcvbuf = s.GetInt("openvpn.rcvbuf");

            if (rcvbuf == -2)
            {
                rcvbuf = Platform.Instance.GetRecommendedRcvBufDirective();
            }
            if (rcvbuf == -2)
            {
                rcvbuf = -1;
            }
            if (rcvbuf != -1)
            {
                ovpn.AppendDirective("rcvbuf", rcvbuf.ToString(), "");
            }

            int sndbuf = s.GetInt("openvpn.sndbuf");

            if (sndbuf == -2)
            {
                sndbuf = Platform.Instance.GetRecommendedSndBufDirective();
            }
            if (sndbuf == -2)
            {
                sndbuf = -1;
            }
            if (sndbuf != -1)
            {
                ovpn.AppendDirective("sndbuf", sndbuf.ToString(), "");
            }

            string proxyDirectiveName = "";
            string proxyDirectiveArgs = "";

            string proxyMode = s.GetLower("proxy.mode");
            string proxyWhen = s.GetLower("proxy.when");

            if ((proxyWhen == "none") || (proxyWhen == "web"))
            {
                proxyMode = "none";
            }
            if (proxyMode == "tor")
            {
                proxyDirectiveName = "socks-proxy";
            }
            else if (proxyMode == "http")
            {
                proxyDirectiveName = "http-proxy";
            }
            else if (proxyMode == "socks")
            {
                proxyDirectiveName = "socks-proxy";
            }

            if (proxyDirectiveName != "")
            {
                proxyDirectiveArgs += s.Get("proxy.host") + " " + s.Get("proxy.port");

                if ((s.GetLower("proxy.mode") != "none") && (s.GetLower("proxy.mode") != "tor"))
                {
                    if (s.Get("proxy.auth") != "None")
                    {
                        string fileNameAuthOvpn = "";
                        if (preview)
                        {
                            fileNameAuthOvpn = "dummy.ppw";
                        }
                        else
                        {
                            connectionActive.ProxyAuthFile = new TemporaryFile("ppw");
                            fileNameAuthOvpn = connectionActive.ProxyAuthFile.Path;
                            string fileNameData = s.Get("proxy.login") + "\n" + s.Get("proxy.password") + "\n";
                            Platform.Instance.FileContentsWriteText(connectionActive.ProxyAuthFile.Path, fileNameData, Encoding.Default);                             // TOFIX: Check if OpenVPN expect UTF-8
                            Platform.Instance.FileEnsurePermission(connectionActive.ProxyAuthFile.Path, "600");
                        }
                        proxyDirectiveArgs += " " + ovpn.EncodePath(fileNameAuthOvpn) + " " + s.Get("proxy.auth").ToLowerInvariant();                         // 2.6 Auth Fix
                    }
                }

                ovpn.AppendDirective(proxyDirectiveName, proxyDirectiveArgs, "");
            }

            if (Constants.FeatureIPv6ControlOptions)
            {
                if (s.GetLower("network.ipv4.mode") == "in")
                {
                    connectionActive.TunnelIPv4 = true;
                }
                else if (s.GetLower("network.ipv4.mode") == "in-out")
                {
                    if (SupportIPv4)
                    {
                        connectionActive.TunnelIPv4 = true;
                    }
                    else
                    {
                        connectionActive.TunnelIPv4 = false;
                    }
                }
                else if (s.GetLower("network.ipv4.mode") == "in-block")
                {
                    if (SupportIPv4)
                    {
                        connectionActive.TunnelIPv4 = true;
                    }
                    else
                    {
                        connectionActive.TunnelIPv4 = false;                         // Out, but doesn't matter, will be blocked.
                    }
                }
                else if (s.GetLower("network.ipv4.mode") == "out")
                {
                    connectionActive.TunnelIPv4 = false;
                }
                else if (s.GetLower("network.ipv4.mode") == "block")
                {
                    connectionActive.TunnelIPv4 = false;                     // Out, but doesn't matter, will be blocked.
                }

                if (Engine.Instance.GetNetworkIPv6Mode() == "in")
                {
                    connectionActive.TunnelIPv6 = true;
                }
                else if (Engine.Instance.GetNetworkIPv6Mode() == "in-out")
                {
                    if (SupportIPv6)
                    {
                        connectionActive.TunnelIPv6 = true;
                    }
                    else
                    {
                        connectionActive.TunnelIPv6 = false;
                    }
                }
                else if (Engine.Instance.GetNetworkIPv6Mode() == "in-block")
                {
                    if (SupportIPv6)
                    {
                        connectionActive.TunnelIPv6 = true;
                    }
                    else
                    {
                        connectionActive.TunnelIPv6 = false;
                    }
                }
                else if (Engine.Instance.GetNetworkIPv6Mode() == "out")
                {
                    connectionActive.TunnelIPv6 = false;
                }
                else if (Engine.Instance.GetNetworkIPv6Mode() == "block")
                {
                    connectionActive.TunnelIPv6 = false;
                }

                if (Software.GetTool("openvpn").VersionAboveOrEqual("2.4"))
                {
                    ovpn.RemoveDirective("redirect-gateway");                     // Remove if exists
                    ovpn.AppendDirective("pull-filter", "ignore \"redirect-gateway\"", "Forced at client side");

                    if (connectionActive.TunnelIPv6 == false)
                    {
                        ovpn.AppendDirective("pull-filter", "ignore \"dhcp-option DNS6\"", "Client side");
                        ovpn.AppendDirective("pull-filter", "ignore \"tun-ipv6\"", "Client side");
                        ovpn.AppendDirective("pull-filter", "ignore \"ifconfig-ipv6\"", "Client side");
                    }

                    if ((connectionActive.TunnelIPv4 == false) && (connectionActive.TunnelIPv6 == false))
                    {
                        // no redirect-gateway
                    }
                    else if ((connectionActive.TunnelIPv4 == true) && (connectionActive.TunnelIPv6 == false))
                    {
                        ovpn.AppendDirective("redirect-gateway", "def1 bypass-dhcp", "");
                    }
                    else if ((connectionActive.TunnelIPv4 == false) && (connectionActive.TunnelIPv6 == true))
                    {
                        ovpn.AppendDirective("redirect-gateway", "ipv6 !ipv4 def1 bypass-dhcp", "");
                    }
                    else
                    {
                        ovpn.AppendDirective("redirect-gateway", "ipv6 def1 bypass-dhcp", "");
                    }
                }
                else
                {
                    // OpenVPN <2.4, IPv6 not supported, IPv4 required.
                    connectionActive.TunnelIPv4 = true;
                    connectionActive.TunnelIPv6 = false;

                    if (connectionActive.TunnelIPv4)
                    {
                        ovpn.AppendDirective("redirect-gateway", "def1 bypass-dhcp", "");
                    }
                    else
                    {
                        ovpn.AppendDirective("route-nopull", "", "For Routes Out");

                        // 2.9, this is used by Linux resolv-conf DNS method. Need because route-nopull also filter pushed dhcp-option.
                        // Incorrect with other provider, but the right-approach (pull-filter based) require OpenVPN <2.4.
                        ovpn.AppendDirective("dhcp-option", "DNS " + Constants.DnsVpn, "");
                    }
                }
            }
            else
            {
                string routesDefault = s.Get("routes.default");

                connectionActive.TunnelIPv4 = (routesDefault == "in");
                connectionActive.TunnelIPv6 = (routesDefault == "in");

                if (routesDefault == "out")
                {
                    if (Software.GetTool("openvpn").VersionAboveOrEqual("2.4"))
                    {
                        ovpn.RemoveDirective("redirect-gateway");                         // Remove if exists
                        ovpn.AppendDirective("pull-filter", "ignore \"redirect-gateway\"", "For Routes Out");
                    }
                    else                     // Compatibility <2.4
                    {
                        ovpn.AppendDirective("route-nopull", "", "For Routes Out");

                        // For DNS
                        // < 2.9. route directive useless, and DNS are forced manually in every supported platform. // TOCLEAN

                        /*
                         * ovpn += "dhcp-option DNS " + Constants.DnsVpn + "\n"; // Manually because route-nopull skip it
                         * ovpn += "route 10.4.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         * ovpn += "route 10.5.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         * ovpn += "route 10.6.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         * ovpn += "route 10.7.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         * ovpn += "route 10.8.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         * ovpn += "route 10.9.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         * ovpn += "route 10.30.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         * ovpn += "route 10.50.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                         */

                        // 2.9, this is used by Linux resolv-conf DNS method. Need because route-nopull also filter pushed dhcp-option.
                        // Incorrect with other provider, but the right-approach (pull-filter based) require OpenVPN <2.4.
                        ovpn.AppendDirective("dhcp-option", "DNS " + Constants.DnsVpn, "");
                    }
                }
            }

            // For Checking
            foreach (IpAddress ip in IpsExit.IPs)
            {
                connectionActive.AddRoute(ip, "vpn_gateway", "For Checking Route");
            }

            string routes = s.Get("routes.custom");

            string[] routes2 = routes.Split(';');
            foreach (string route in routes2)
            {
                string[] routeEntries = route.Split(',');
                if (routeEntries.Length != 3)
                {
                    continue;
                }

                string      ipCustomRoute  = routeEntries[0];
                IpAddresses ipsCustomRoute = new IpAddresses(ipCustomRoute);

                if (ipsCustomRoute.Count == 0)
                {
                    Engine.Instance.Logs.Log(LogType.Verbose, LanguageManager.GetText("CustomRouteInvalid", ipCustomRoute.ToString()));
                }
                else
                {
                    string action = routeEntries[1];
                    string notes  = routeEntries[2];

                    foreach (IpAddress ip in ipsCustomRoute.IPs)
                    {
                        bool layerIn = false;
                        if (ip.IsV4)
                        {
                            layerIn = connectionActive.TunnelIPv4;
                        }
                        else if (ip.IsV6)
                        {
                            layerIn = connectionActive.TunnelIPv6;
                        }
                        string gateway = "";
                        if ((layerIn == false) && (action == "in"))
                        {
                            gateway = "vpn_gateway";
                        }
                        if ((layerIn == true) && (action == "out"))
                        {
                            gateway = "net_gateway";
                        }
                        if (gateway != "")
                        {
                            connectionActive.AddRoute(ip, gateway, (notes != "") ? notes.Safe() : ipCustomRoute);
                        }
                    }
                }
            }

            if (proxyMode == "tor")
            {
                if (preview == false)
                {
                    TorControl.SendNEWNYM();
                }
                IpAddresses torNodeIps = TorControl.GetGuardIps((preview == false));
                foreach (IpAddress torNodeIp in torNodeIps.IPs)
                {
                    if (((connectionActive.TunnelIPv4) && (torNodeIp.IsV4)) ||
                        ((connectionActive.TunnelIPv6) && (torNodeIp.IsV6)))
                    {
                        connectionActive.AddRoute(torNodeIp, "net_gateway", "Tor Guard");
                    }
                }
            }

            {
                string managementPasswordFile = "dummy.ppw";
                if (preview == false)
                {
                    connectionActive.ManagementPassword     = RandomGenerator.GetHash();
                    connectionActive.ManagementPasswordFile = new TemporaryFile("ppw");
                    managementPasswordFile = connectionActive.ManagementPasswordFile.Path;
                    Platform.Instance.FileContentsWriteText(managementPasswordFile, connectionActive.ManagementPassword, Encoding.ASCII); // UTF8 not recognized by OpenVPN
                    Platform.Instance.FileEnsurePermission(managementPasswordFile, "600");
                }

                ovpn.AppendDirective("management", "127.0.0.1 " + Engine.Instance.Storage.Get("openvpn.management_port") + " " + ovpn.EncodePath(managementPasswordFile), "");
            }

            // Experimental - Allow identification as Public Network in Windows. Advanced Option?
            // ovpn.Append("route-metric 512");
            // ovpn.Append("route 0.0.0.0 0.0.0.0");

            Provider.OnBuildConnectionActive(this, connectionActive);

            Provider.OnBuildConnectionActiveAuth(connectionActive);

            Platform.Instance.OnBuildOvpn(ovpn);

            ovpn.AppendDirectives(Engine.Instance.Storage.Get("openvpn.custom"), "Custom level");

            foreach (ConnectionActiveRoute route in connectionActive.Routes)
            {
                if ((route.Address.IsV6) || (Constants.FeatureAlwaysBypassOpenvpnRoute))
                {
                }
                else
                {
                    // We never find a better method to manage IPv6 route via OpenVPN, at least <2.4.4
                    ovpn.AppendDirective("route", route.Address.ToOpenVPN() + " " + route.Gateway, route.Notes.Safe());
                }
            }

            ovpn.Normalize();

            return(connectionActive);
        }
Example #7
0
        public OvpnBuilder BuildOVPN(bool preview)
        {
            // If preview, no physical additional files are created.

            Storage s = Engine.Instance.Storage;

            OvpnBuilder ovpn = new OvpnBuilder();

            if (s.GetBool("openvpn.skip_defaults") == false)
            {
                ovpn.AppendDirectives(Engine.Instance.Storage.Get("openvpn.directives"), "Client level");
                string directivesPath = Engine.Instance.Storage.Get("openvpn.directives.path");
                if (directivesPath.Trim() != "")
                {
                    try
                    {
                        if (Platform.Instance.FileExists(directivesPath))
                        {
                            string text = Platform.Instance.FileContentsReadText(directivesPath);
                            ovpn.AppendDirectives(text, "Client level");
                        }
                        else
                        {
                            Engine.Instance.Logs.Log(LogType.Warning, MessagesFormatter.Format(Messages.FileNotFound, directivesPath));
                        }
                    }
                    catch (Exception ex)
                    {
                        Engine.Instance.Logs.Log(LogType.Warning, MessagesFormatter.Format(Messages.FileErrorRead, directivesPath, ex.Message));
                    }
                }
                Provider.OnBuildOvpnDefaults(ovpn);

                ovpn.AppendDirectives(OvpnDirectives, "Server level");

                if (Path != "")
                {
                    if (Platform.Instance.FileExists(Path))
                    {
                        string text = Platform.Instance.FileContentsReadText(Path);
                        ovpn.AppendDirectives(text, "Config file");

                        string dirPath = Platform.Instance.FileGetDirectoryPath(Path);
                        ovpn.NormalizeRelativePath(dirPath);
                    }
                }
            }

            if (s.Get("openvpn.dev_node") != "")
            {
                ovpn.AppendDirective("dev-node", s.Get("openvpn.dev_node"), "");
            }

            int rcvbuf = s.GetInt("openvpn.rcvbuf");

            if (rcvbuf == -2)
            {
                rcvbuf = Platform.Instance.GetRecommendedRcvBufDirective();
            }
            if (rcvbuf == -2)
            {
                rcvbuf = -1;
            }
            if (rcvbuf != -1)
            {
                ovpn.AppendDirective("rcvbuf", rcvbuf.ToString(), "");
            }

            int sndbuf = s.GetInt("openvpn.sndbuf");

            if (sndbuf == -2)
            {
                sndbuf = Platform.Instance.GetRecommendedSndBufDirective();
            }
            if (sndbuf == -2)
            {
                sndbuf = -1;
            }
            if (sndbuf != -1)
            {
                ovpn.AppendDirective("sndbuf", sndbuf.ToString(), "");
            }

            string proxyDirectiveName = "";
            string proxyDirectiveArgs = "";

            string proxyMode = s.GetLower("proxy.mode");
            string proxyWhen = s.GetLower("proxy.when");

            if ((proxyWhen == "none") || (proxyWhen == "web"))
            {
                proxyMode = "none";
            }
            if (proxyMode == "tor")
            {
                proxyDirectiveName = "socks-proxy";
            }
            else if (proxyMode == "http")
            {
                proxyDirectiveName = "http-proxy";
            }
            else if (proxyMode == "socks")
            {
                proxyDirectiveName = "socks-proxy";
            }

            if (proxyDirectiveName != "")
            {
                proxyDirectiveArgs += s.Get("proxy.host") + " " + s.Get("proxy.port");

                if ((s.GetLower("proxy.mode") != "none") && (s.GetLower("proxy.mode") != "tor"))
                {
                    if (s.Get("proxy.auth") != "None")
                    {
                        string fileNameAuthOvpn = "";
                        if (preview)
                        {
                            fileNameAuthOvpn = "dummy.ppw";
                        }
                        else
                        {
                            ovpn.FileProxyAuth = new TemporaryFile("ppw");
                            fileNameAuthOvpn   = ovpn.FileProxyAuth.Path.Replace("\\", "\\\\");                           // 2.6, Escaping for Windows
                            string fileNameData = s.Get("proxy.login") + "\n" + s.Get("proxy.password") + "\n";
                            Platform.Instance.FileContentsWriteText(ovpn.FileProxyAuth.Path, fileNameData);
                            Platform.Instance.FileEnsurePermission(ovpn.FileProxyAuth.Path, "600");
                        }
                        proxyDirectiveArgs += " \"" + fileNameAuthOvpn + "\" " + s.Get("proxy.auth").ToLowerInvariant();                         // 2.6 Auth Fix
                    }
                }

                ovpn.AppendDirective(proxyDirectiveName, proxyDirectiveArgs, "");
            }

            if (Lib.Common.Constants.AlphaFeatures)
            {
                if (Software.GetTool("openvpn").VersionAboveOrEqual("2.4"))
                {
                    // IP Layer routes

                    ovpn.AppendDirective("pull-filter", "ignore \"redirect-gateway\"", "Forced at client side");

                    bool ipv4In = true;
                    bool ipv6In = true;

                    if (s.GetLower("protocol.ipv4.route") == "in-always")
                    {
                        ipv4In = true;
                    }
                    else if (s.GetLower("protocol.ipv4.route") == "in-out")
                    {
                        if (SupportIPv4)
                        {
                            ipv4In = true;
                        }
                        else
                        {
                            ipv4In = false;
                        }
                    }
                    else if (s.GetLower("protocol.ipv4.route") == "in-block")
                    {
                        if (SupportIPv4)
                        {
                            ipv4In = true;
                        }
                        else
                        {
                            ipv4In = false;                             // Out, but doesn't matter, will be blocked.
                        }
                    }
                    else if (s.GetLower("protocol.ipv4.route") == "out")
                    {
                        ipv4In = false;
                    }
                    else if (s.GetLower("protocol.ipv4.route") == "block")
                    {
                        ipv4In = false;                         // Out, but doesn't matter, will be blocked.
                    }

                    if (s.GetLower("protocol.ipv6.route") == "in-always")
                    {
                        ipv6In = true;
                    }
                    else if (s.GetLower("protocol.ipv6.route") == "in-out")
                    {
                        if (SupportIPv4)
                        {
                            ipv6In = true;
                        }
                        else
                        {
                            ipv6In = false;
                        }
                    }
                    else if (s.GetLower("protocol.ipv6.route") == "in-block")
                    {
                        if (SupportIPv6)
                        {
                            ipv6In = true;
                        }
                        else
                        {
                            ipv6In = false;                             // Out, but doesn't matter, will be blocked.
                        }
                    }
                    else if (s.GetLower("protocol.ipv6.route") == "out")
                    {
                        ipv6In = false;
                    }
                    else if (s.GetLower("protocol.ipv6.route") == "block")
                    {
                        ipv6In = false;                         // Out, but doesn't matter, will be blocked.
                    }

                    if ((ipv4In == false) && (ipv6In == false))
                    {
                        // no redirect-gateway
                    }
                    else if ((ipv4In == true) && (ipv6In == false))
                    {
                        ovpn.AppendDirective("redirect-gateway", "def1 bypass-dhcp", "");
                    }
                    else if ((ipv4In == false) && (ipv6In == true))
                    {
                        ovpn.AppendDirective("redirect-gateway", "ipv6 !ipv4 def1 bypass-dhcp", "");
                    }
                    else
                    {
                        ovpn.AppendDirective("redirect-gateway", "ipv6 def1 bypass-dhcp", "");
                    }
                }
                else
                {
                    // ClodoTemp: If <2.4 ? Ipv6 are anyway non managed well.
                }
            }
            else
            {
            }

            string routesDefault = s.Get("routes.default");

            if (routesDefault == "out")
            {
                if (Software.GetTool("openvpn").VersionAboveOrEqual("2.4"))
                {
                    ovpn.RemoveDirective("redirect-gateway");                     // Remove if exists
                    ovpn.AppendDirective("pull-filter", "ignore \"redirect-gateway\"", "For Routes Out");
                }
                else                 // Compatibility <2.4
                {
                    ovpn.AppendDirective("route-nopull", "", "For Routes Out");

                    // For DNS
                    // < 2.9. route directive useless, and DNS are forced manually in every supported platform. // TOCLEAN

                    /*
                     * ovpn += "dhcp-option DNS " + Constants.DnsVpn + "\n"; // Manually because route-nopull skip it
                     * ovpn += "route 10.4.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     * ovpn += "route 10.5.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     * ovpn += "route 10.6.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     * ovpn += "route 10.7.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     * ovpn += "route 10.8.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     * ovpn += "route 10.9.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     * ovpn += "route 10.30.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     * ovpn += "route 10.50.0.1 255.255.255.255 vpn_gateway # AirDNS\n";
                     */

                    // 2.9, Can be removed when resolv-conf method it's not binded anymore in up/down ovpn directive // TOFIX
                    ovpn.AppendDirective("dhcp-option", "DNS " + Lib.Common.Constants.DnsVpn, "");
                }

                // For Checking
                foreach (IpAddress ip in IpsExit.IPs)
                {
                    if (ip.IsV4)                    // TOFIX IPv6
                    {
                        ovpn.AppendDirective("route", ip.ToOpenVPN() + " vpn_gateway", "For Checking Route");
                    }
                }
            }

            string routes = s.Get("routes.custom");

            string[] routes2 = routes.Split(';');
            foreach (string route in routes2)
            {
                string[] routeEntries = route.Split(',');
                if (routeEntries.Length != 3)
                {
                    continue;
                }

                string      ipCustomRoute  = routeEntries[0];
                IpAddresses ipsCustomRoute = new IpAddresses(ipCustomRoute);

                if (ipsCustomRoute.Count == 0)
                {
                    Engine.Instance.Logs.Log(LogType.Verbose, MessagesFormatter.Format(Messages.CustomRouteInvalid, ipCustomRoute.ToString()));
                }
                else
                {
                    string action = routeEntries[1];
                    string notes  = routeEntries[2];

                    string gateway = "";

                    if ((routesDefault == "out") && (action == "in"))
                    {
                        gateway = "vpn_gateway";
                    }
                    if ((routesDefault == "in") && (action == "out"))
                    {
                        gateway = "net_gateway";
                    }


                    if (gateway != "")
                    {
                        foreach (IpAddress ip in ipsCustomRoute.IPs)
                        {
                            if (ip.IsV4)
                            {
                                ovpn.AppendDirective("route", ip.ToOpenVPN() + " " + gateway, (notes != "") ? Utils.StringSafe(notes) : ipCustomRoute);
                            }
                            // TOFIX IPv6

                            /*
                             * else if(ipCustomRoute.IsV6)
                             *      ovpn.AppendDirective("route-ipv6", ipCustomRoute.ToOpenVPN() + " " + gateway + "_ipv6", Utils.StringSafe(notes));
                             */
                        }
                    }
                }
            }

            if (routesDefault == "in")
            {
                if (proxyMode == "tor")
                {
                    IpAddresses torNodeIps = TorControl.GetGuardIps();
                    foreach (IpAddress torNodeIp in torNodeIps.IPs)
                    {
                        if (torNodeIp.IsV4)
                        {
                            ovpn.AppendDirective("route", torNodeIp.ToOpenVPN() + " net_gateway", "Tor Circuit");
                        }
                        // TOFIX IPv6

                        /*
                         * else if(torNodeIp.IsV6)
                         *      ovpn.AppendDirective("route-ipv6", torNodeIp.ToOpenVPN() + " net_gateway_ipv6", "Tor Circuit");
                         */
                    }
                }
            }

            ovpn.AppendDirective("management", "127.0.0.1 " + Engine.Instance.Storage.Get("openvpn.management_port"), "");

            ovpn.AppendDirectives(Engine.Instance.Storage.Get("openvpn.custom"), "Custom level");

            // Experimental - Allow identification as Public Network in Windows. Advanced Option?
            // ovpn.Append("route-metric 512");
            // ovpn.Append("route 0.0.0.0 0.0.0.0");

            Provider.OnBuildOvpn(this, ovpn);

            Provider.OnBuildOvpnAuth(ovpn);

            Platform.Instance.OnBuildOvpn(ovpn);

            ovpn.Normalize();

            string ovpnText = ovpn.Get();

            Provider.OnBuildOvpnPost(ref ovpnText);

            return(ovpn);
        }