Пример #1
0
		/*
		public void Start()
		{
			T = new System.Threading.Thread(new ThreadStart(this.Run));
			T.Priority = ThreadPriority.Lowest;
			T.Start();
		}
		*/

		public void Run()
		{
			RouteScope routeScope = null;
			try
			{
				//bool alwaysRun = Engine.Instance.Storage.GetBool("advanced.pinger.always"); // 2.6
				routeScope = new RouteScope(Server.IpEntry);

				// Ping
				Ping pingSender = new Ping();
				PingOptions options = new PingOptions();

				// Use the default Ttl value which is 128,
				// but change the fragmentation behavior.
				options.DontFragment = true;

				// Create a buffer of 32 bytes of data to be transmitted.								
				byte[] buffer = RandomGenerator.GetBuffer(32);
				int timeout = 5000;
				PingReply reply = pingSender.Send(Server.IpEntry, timeout, buffer, options);
				Pinger.Instance.PingResult(Server, reply);
			}
			catch (Exception)
			{				
				Pinger.Instance.PingResult(Server, -1);
			}
			finally
			{
				if (routeScope != null)
				{
					routeScope.End();
				}

				lock (Pinger.Instance.Jobs)
				{
					Pinger.Instance.Jobs.Remove(this);
				}
			}

		}
Пример #2
0
		public static XmlDocument Fetch(string title, Dictionary<string, string> parameters)
		{
			parameters["login"] = Engine.Instance.Storage.Get("login");
			parameters["password"] = Engine.Instance.Storage.Get("password");
			parameters["system"] = Platform.Instance.GetSystemCode();
			parameters["version"] = Constants.VersionInt.ToString(CultureInfo.InvariantCulture);

			List<string> hosts = new List<string>();
			
			if (Engine.Instance.Storage.Manifest != null)
			{
				XmlNodeList nodesHosts = Engine.Instance.Storage.Manifest.SelectNodes("//hosts/host");
				foreach (XmlNode nodeHost in nodesHosts)
				{
					hosts.Add(nodeHost.Attributes["address"].Value);
				}
			}

			// Debugging
			// hosts.Clear();
			// hosts.Add("invalidhostname.airvpn.org");
			// hosts.Add("54.246.124.152");
			
			string firstError = "";
			int hostN = 0;
			foreach (string host in hosts)
			{
				hostN++;
				if (Utils.IsIP(host) == false)
				{
					// If locked network are enabled, skip the hostname and try only by IP.
					// To avoid DNS issue (generally, to avoid losing time).
					if (Engine.Instance.NetworkLockManager.IsDnsResolutionAvailable(host) == false)
						continue;					
				}

				try
				{
					RouteScope routeScope = new RouteScope(host);
					XmlDocument xmlDoc = AirExchange.FetchHost(host, parameters);
					routeScope.End();
					if (xmlDoc == null)
						throw new Exception("No answer.");

					if (xmlDoc.DocumentElement.Attributes["error"] != null)
						throw new Exception(xmlDoc.DocumentElement.Attributes["error"].Value);

					return xmlDoc;
				}
				catch (Exception e)
				{
					string info = e.Message;
					string proxyMode = Engine.Instance.Storage.Get("proxy.mode").ToLowerInvariant();
					string proxyAuth = Engine.Instance.Storage.Get("proxy.auth").ToLowerInvariant();
					if (proxyMode != "none")
						info += ", with '" + proxyMode + "' proxy and '" + proxyAuth + "' auth";

					if (Engine.Instance.Storage.GetBool("advanced.expert"))
						Engine.Instance.Log(Engine.LogType.Verbose, Messages.Format(Messages.ExchangeTryFailed, title, hostN.ToString(), info));

					if (firstError == "")
						firstError = info;
				}
			}

			throw new Exception(firstError);			
		}
Пример #3
0
        public static XmlDocument Fetch(string title, Dictionary <string, string> parameters)
        {
            parameters["login"]    = Engine.Instance.Storage.Get("login");
            parameters["password"] = Engine.Instance.Storage.Get("password");
            parameters["system"]   = Platform.Instance.GetSystemCode();
            parameters["version"]  = Constants.VersionInt.ToString(CultureInfo.InvariantCulture);

            List <string> hosts = new List <string>();

            if (Engine.Instance.Storage.Manifest != null)
            {
                XmlNodeList nodesHosts = Engine.Instance.Storage.Manifest.SelectNodes("//hosts/host");
                foreach (XmlNode nodeHost in nodesHosts)
                {
                    hosts.Add(nodeHost.Attributes["address"].Value);
                }
            }

            // Debugging

            /*
             * hosts.Clear();
             * hosts.Add("invalidhostname.airvpn.org");
             * hosts.Add("54.93.175.114");
             */

            string firstError = "";
            int    hostN      = 0;

            foreach (string host in hosts)
            {
                hostN++;
                if (Utils.IsIP(host) == false)
                {
                    // If locked network are enabled, skip the hostname and try only by IP.
                    // To avoid DNS issue (generally, to avoid losing time).
                    if (Engine.Instance.NetworkLockManager.IsDnsResolutionAvailable(host) == false)
                    {
                        continue;
                    }
                }

                try
                {
                    RouteScope  routeScope = new RouteScope(host);
                    XmlDocument xmlDoc     = AirExchange.FetchHost(host, parameters);
                    routeScope.End();
                    if (xmlDoc == null)
                    {
                        throw new Exception("No answer.");
                    }

                    if (xmlDoc.DocumentElement.Attributes["error"] != null)
                    {
                        throw new Exception(xmlDoc.DocumentElement.Attributes["error"].Value);
                    }

                    return(xmlDoc);
                }
                catch (Exception e)
                {
                    string info      = e.Message;
                    string proxyMode = Engine.Instance.Storage.Get("proxy.mode").ToLowerInvariant();
                    string proxyAuth = Engine.Instance.Storage.Get("proxy.auth").ToLowerInvariant();
                    if (proxyMode != "none")
                    {
                        info += ", with '" + proxyMode + "' proxy and '" + proxyAuth + "' auth";
                    }
                    Engine.Instance.Log(Engine.LogType.Verbose, Messages.Format(Messages.ExchangeTryFailed, title, hostN.ToString(), info));

                    if (firstError == "")
                    {
                        firstError = e.Message;
                    }
                }
            }

            throw new Exception(firstError);
        }
Пример #4
0
		public override void OnRun()
		{
			CancelRequested = false;

			string sessionLastServer = "";

			bool oneConnectionReached = false;

			for (; CancelRequested == false; )
			{
				RouteScope routeScope = null;

				bool allowed = true;
				string waitingMessage = "";
				int waitingSecs = 0;
				m_processOpenVpn = null;
				m_processProxy = null;

				try
				{
					// -----------------------------------
					// Phase 1: Initialization and start
					// -----------------------------------

					
					if ((Engine.NextServer == null) && (Pinger.Instance.GetEnabled()) && (Engine.PingerInvalid() != 0))
					{
						string lastWaitingMessage = "";
						for (; ; )
						{
							if (CancelRequested)
								break;

							int i = Engine.PingerInvalid();
							if (i == 0)
								break;

							string nextWaitingMessage = Messages.WaitingLatencyTestsTitle + " " + Messages.Format(Messages.WaitingLatencyTestsStep, i.ToString());
							if (lastWaitingMessage != nextWaitingMessage)
							{
								lastWaitingMessage = nextWaitingMessage;
								Engine.WaitMessageSet(nextWaitingMessage, true);
							}
							
							Sleep(100);
						}
					}

					if (CancelRequested)
						continue;

					m_openVpnManagementCommands.Clear();

					string protocol = Engine.Storage.Get("mode.protocol").ToUpperInvariant();
					int port = Engine.Storage.GetInt("mode.port");
					int alt = Engine.Storage.GetInt("mode.alt");

					if (protocol == "AUTO")
					{						
						protocol = Engine.Storage.GetManifestKeyValue("mode_protocol", "UDP");
						port = Conversions.ToInt32(Engine.Storage.GetManifestKeyValue("mode_port", "443"));
						alt = Conversions.ToInt32(Engine.Storage.GetManifestKeyValue("mode_alt", "0"));
					}

					if (protocol == "SSH")
					{
						m_proxyPort = Engine.Storage.GetInt("ssh.port");
						if (m_proxyPort == 0)
							m_proxyPort = RandomGenerator.GetInt(1024, 64 * 1024);
					}
					else if (protocol == "SSL")
					{
						m_proxyPort = Engine.Storage.GetInt("ssl.port");
						if (m_proxyPort == 0)
							m_proxyPort = RandomGenerator.GetInt(1024, 64 * 1024);
					}
					else
					{
						m_proxyPort = 0;
					}

					Engine.CurrentServer = Engine.NextServer;
					Engine.NextServer = null;

					if (Engine.Storage.Get("server") != "")
					{
						Engine.CurrentServer = Engine.PickServer(Engine.Storage.Get("server"), true);
					}
					else
					{
						if (Engine.CurrentServer == null)
							if (Engine.Storage.GetBool("servers.locklast"))
								Engine.CurrentServer = Engine.PickServer(sessionLastServer, false);

						if (Engine.CurrentServer == null)
							Engine.CurrentServer = Engine.PickServer();
					}

					if (Engine.CurrentServer == null)
					{
						allowed = false;
						Engine.Log(Core.Engine.LogType.Fatal, "No server available.");
						RequestStop();
					}
					
					// Checking auth user status.
					// Only to avoid a generic AUTH_FAILED. For that we don't report here for ex. the sshtunnel keys.
					if (allowed)
					{
						Engine.WaitMessageSet(Messages.AuthorizeConnect, true);
						Engine.Log(Engine.LogType.Info, Messages.AuthorizeConnect);

						Dictionary<string, string> parameters = new Dictionary<string, string>();
						parameters["act"] = "connect";
						parameters["server"] = Engine.CurrentServer.Name;
						parameters["protocol"] = protocol;
						parameters["port"] = port.ToString();
						parameters["alt"] = alt.ToString();

						XmlDocument xmlDoc = null;
						try
						{
							xmlDoc = AirExchange.Fetch(Messages.AuthorizeConnect, parameters);
						}
						catch (Exception e)
						{
							// Note: If failed, continue anyway.
							Engine.Log(Engine.LogType.Warning, Messages.Format(Messages.AuthorizeConnectFailed, e.Message));
						}

						if (xmlDoc != null) 
						{
							string userMessage = Utils.XmlGetAttributeString(xmlDoc.DocumentElement, "message", "");							
							if (userMessage != "")
							{
								allowed = false;
								string userMessageAction = Utils.XmlGetAttributeString(xmlDoc.DocumentElement, "message_action", "");								
								if (userMessageAction == "stop")
								{
									Engine.Log(Core.Engine.LogType.Fatal, userMessage);
									Engine.Disconnect(); // 2.8
									RequestStop();
								}
								else if (userMessageAction == "next")
								{
									Engine.CurrentServer.Penality += Engine.Storage.GetInt("advanced.penality_on_error");
									waitingMessage = userMessage + ", next in {1} sec.";
									waitingSecs = 5;
								}
								else 
								{
									waitingMessage = userMessage + ", retry in {1} sec.";
									waitingSecs = 10;
								}
							}
						}
					}

					if (CancelRequested)
						continue;

					if (allowed)
					{
						sessionLastServer = Engine.CurrentServer.Name;
						Engine.Storage.Set("servers.last", Engine.CurrentServer.Name);


						if (Engine.CurrentServer.ServerType == 2)
						{
							// Routing servers have only 443-UDP-1ip
							protocol = "UDP";
							port = 443;
							alt = 0;
						}

						routeScope = new RouteScope(Engine.ConnectedEntryIP);

						Engine.RunEventCommand("vpn.pre");

						string connectingMessage = Messages.Format(Messages.ConnectionConnecting, Engine.CurrentServer.PublicName, Engine.CurrentServer.CountryName, Engine.CurrentServer.Location);
						Engine.WaitMessageSet(connectingMessage, true);
						Engine.Log(Engine.LogType.InfoImportant, connectingMessage);

						Engine.BuildOVPN(protocol, port, alt, m_proxyPort);

						if (protocol == "SSH")
						{
							StartSshProcess();
						}
						else if (protocol == "SSL")
						{
							StartSslProcess();
						}
						else if ((protocol == "TCP") || (protocol == "UDP") || (protocol == "TOR"))
						{
							StartOpenVpnProcess();
						}

						int waitingSleep = 100; // To avoid CPU stress

						m_reset = "";

						// -----------------------------------
						// Phase 2: Waiting connection
						// -----------------------------------

						for (; ; )
						{
							if( (m_processOpenVpn != null) && (m_processOpenVpn.ReallyExited) ) // 2.2
								m_reset = "ERROR";
							if( (m_processProxy != null) && (m_processProxy.ReallyExited) ) // 2.2
								m_reset = "ERROR";

							if (Engine.IsConnected())
								break;

							if (m_reset != "")
								break;

							Sleep(waitingSleep);
						}


						if(m_reset == "")
							oneConnectionReached = true;

						if( (m_reset == "") && (Engine.Instance.Storage.GetBool("advanced.testmode")) )
						{
							m_reset = "STOP";
						}

						// -----------------------------------
						// Phase 3 - Running
						// -----------------------------------

						if (m_reset == "")
						{
							for (; ; )
							{
								int timeNow = Utils.UnixTimeStamp();

								if (Engine.IsConnected() == false)
									throw new Exception("Unexpected.");

								ProcessOpenVpnManagement();

								if (timeNow - m_timeLastStatus >= 1)
								{
									m_timeLastStatus = timeNow;
																		
									// Update traffic stats
									if (Storage.Simulate)
									{
										Engine.Instance.Stats.Charts.Hit(15354, 2525);

										Engine.OnRefreshUi(Core.Engine.RefreshUiMode.Stats);
									}
									else if(Platform.Instance.GetTunStatsMode() == "NetworkInterface")
									{
										if (m_interfaceTun != null)
										{
											Int64 read = m_interfaceTun.GetIPv4Statistics().BytesReceived;
											Int64 write = m_interfaceTun.GetIPv4Statistics().BytesSent;

											if (Engine.ConnectedLastRead != -1)
											{
												int delta = Engine.ConnectedLastStatsTick.Reset();
												if (delta > 0)
												{
													Engine.ConnectedLastDownloadStep = (1000 * (read - Engine.ConnectedLastRead)) / delta;
													Engine.ConnectedLastUploadStep = (1000 * (write - Engine.ConnectedLastWrite)) / delta;
												}
											}

											Engine.ConnectedLastRead = read;
											Engine.ConnectedLastWrite = write;

											Engine.Instance.Stats.Charts.Hit(Engine.ConnectedLastDownloadStep, Engine.ConnectedLastUploadStep);

											Engine.OnRefreshUi(Core.Engine.RefreshUiMode.Stats);
										}
									}
									else if (Platform.Instance.GetTunStatsMode() == "OpenVpnManagement")
									{
										SendManagementCommand("status");
									}
								}
																
								// Need stop?
								bool StopRequest = false;

								if (m_reset == "RETRY")
								{
									StopRequest = true;
								}

								if (m_reset == "ERROR")
								{
									Engine.CurrentServer.Penality += Engine.Storage.GetInt("advanced.penality_on_error");
									StopRequest = true;
								}

								if (Engine.NextServer != null)
								{
									StopRequest = true;
								}

								if (Engine.SwitchServer != false)
								{
									Engine.SwitchServer = false;
									StopRequest = true;
								}

								if (CancelRequested)
									StopRequest = true;

								if (StopRequest)
									break;

								Sleep(waitingSleep);
							}
						}

						// -----------------------------------
						// Phase 4 - Start disconnection
						// -----------------------------------

						Engine.SetConnected(false);

						Engine.WaitMessageSet(Messages.ConnectionDisconnecting, false);
						Engine.Log(Engine.LogType.InfoImportant, Messages.ConnectionDisconnecting);

						if (Storage.Simulate)
						{
							if (m_processOpenVpn.ReallyExited == false)
								m_processOpenVpn.Kill();
						}

						// -----------------------------------
						// Phase 5 - Waiting disconnection
						// -----------------------------------

						TimeDelta DeltaSigTerm = null;

						for (; ; )
						{
							try
							{
								// As explained here: http://stanislavs.org/stopping-command-line-applications-programatically-with-ctrl-c-events-from-net/
								// there isn't any .Net/Mono clean method to send a signal term to a Windows console-only application. So a brutal Kill is performed when there isn't any alternative.
								// TODO: Maybe optimized under Linux.

								// Simulation process
								if ((Storage.Simulate) && (m_processOpenVpn != null) && (m_processOpenVpn.ReallyExited == false))
									m_processOpenVpn.Kill();

								// OpenVPN process completed, but management socket still opened. Strange, but happen. Closing socket.
								if ((m_processOpenVpn != null) && (m_openVpnManagementSocket != null) && (m_processOpenVpn.ReallyExited == true) && (m_openVpnManagementSocket.Connected))
									m_openVpnManagementSocket.Close();

								// OpenVPN process still exists, but management socket is not connected. We can't tell to OpenVPN to do a plain disconnection, force killing.
								if ((m_processOpenVpn != null) && (m_processOpenVpn.ReallyExited == false))
								{
									if ((m_openVpnManagementSocket == null) || (m_openVpnManagementSocket.Connected == false))
										m_processOpenVpn.Kill();
								}

								// Proxy (SSH/SSL) process								
								if ((m_processProxy != null) && (m_processOpenVpn != null) && (m_processProxy.ReallyExited == false) && (m_processOpenVpn.ReallyExited == true))
								{
									m_processProxy.Kill();
								}

								// Start a clean disconnection
								if ((m_processOpenVpn != null) && (m_openVpnManagementSocket != null) && (m_processOpenVpn.ReallyExited == false) && (m_openVpnManagementSocket.Connected))
								{
									bool sendSignal = false;
									if (DeltaSigTerm == null)
									{
										DeltaSigTerm = new TimeDelta();
										sendSignal = true;
									}
									else if (DeltaSigTerm.Elapsed(10000)) // Try a SIGTERM every 10 seconds
										sendSignal = true;

									if(sendSignal)
									{
										SendManagementCommand("signal SIGTERM");
										ProcessOpenVpnManagement();
									}
								}
							}
							catch (Exception e)
							{
								Engine.Log(Core.Engine.LogType.Warning, e);
							}

							bool exit = true;

							if ((m_openVpnManagementSocket != null) && (m_openVpnManagementSocket.Connected))
								exit = false;

							if ((m_processProxy != null) && (m_processProxy.ReallyExited == false))
								exit = false;

							if ((m_processOpenVpn != null) && (m_processOpenVpn.ReallyExited == false))
								exit = false;

							if (exit)
								break;

							Sleep(waitingSleep);
						}

						// -----------------------------------
						// Phase 6: Cleaning, waiting before retry.
						// -----------------------------------

						Engine.Log(Engine.LogType.Verbose, Messages.ConnectionStop);

						Engine.RunEventCommand("vpn.down");

						Platform.Instance.OnRouteDefaultRemoveRestore();

						Platform.Instance.OnDnsSwitchRestore();

						// Closing temporary files
						if (m_fileSshKey != null)
							m_fileSshKey.Close();
						if (m_fileSslCrt != null)
							m_fileSslCrt.Close();
						if (m_fileSslConfig != null)
							m_fileSslConfig.Close();
						if (m_fileOvpn != null)
							m_fileOvpn.Close();
					}

					

				}
				catch (Exception e)
				{
					// Warning: Avoid to reach this catch: unpredicable status of running processes.
					Engine.SetConnected(false);

					Engine.Log(Core.Engine.LogType.Warning, e);					
				}

				if (routeScope != null)
					routeScope.End();

				if (m_reset == "AUTH_FAILED")
				{
					waitingMessage = "Auth failed, retry in {1} sec.";
					waitingSecs = 10;
				}
				else if (m_reset == "ERROR")
				{
					waitingMessage = "Restart in {1} sec.";
					waitingSecs = 3;
				}
				
				if (Engine.Instance.Storage.GetBool("advanced.testmode"))
				{
					Engine.Instance.RequestStop();
					break;
				}

				if (waitingSecs > 0)
				{
					for (int i = 0; i < waitingSecs; i++)
					{
						Engine.WaitMessageSet(Messages.Format(waitingMessage, (waitingSecs - i).ToString()), true);
						//Engine.Log(Engine.LogType.Verbose, waitingMessage);
						if (CancelRequested)
							break;

						Sleep(1000);
					}
				}
			}

			if (oneConnectionReached == false)
			{
				if (CancelRequested)
				{
					Engine.Log(Engine.LogType.Info, Messages.SessionCancel);
				}
				else
				{
					Engine.Log(Engine.LogType.Error, Messages.SessionFailed);
				}
			}
			
			Engine.Instance.WaitMessageClear();
			
			Engine.CurrentServer = null; 
		}