/// <summary> /// Connect the management logic to OpenVPN /// </summary> protected bool connectLogic() { m_ovpnMLogic.reset(); for (int i = 0; i < 8; ++i) { try { System.Threading.Thread.Sleep(500); // TODO: 500 m_ovpnMLogic.connect(); return(true); } catch (System.Net.Sockets.SocketException ex) { m_logs.logDebugLine(1, "Could not establish connection " + "to management interface:" + ex.Message); if (i != 5) { m_logs.logDebugLine(1, "Trying again in a second"); System.Threading.Thread.Sleep(500); } } } m_logs.logDebugLine(1, "Could not establish connection, abording"); m_state = OVPNState.RUNNING; disconnect(); while (m_state != OVPNState.STOPPED) { Thread.Sleep(200); } changeState(OVPNState.ERROR); return(false); }
/// <summary> /// Start the OpenVPN binary. /// </summary> public void start() { m_logs.logDebugLine(1, "Starting OpenVPN"); m_logs.logLine(OVPNLogEventArgs.LogType.MGNMT, "Starting OpenVPN..."); m_process = new Process(); m_process.StartInfo = m_psi; m_process.Exited += new EventHandler(this.exited_event); m_process.EnableRaisingEvents = true; try { m_process.Start(); } catch (System.ComponentModel.Win32Exception) { m_logs.logLine(OVPNLogEventArgs.LogType.MGNMT, "Could not start OpenVPN"); return; } m_logs.logDebugLine(1, "Started"); m_logs.logLine(OVPNLogEventArgs.LogType.MGNMT, "OpenVPN is running"); running = true; }
/// <summary> /// a line was received, this method parses it and calls methods /// in the management logic. /// </summary> /// <param name="sender">ignored</param> /// <param name="e">information about the received line</param> /// <remarks> /// This method is not thread save! /// But there is no need to call it from more than one thread. /// Only the thread which holds the management connection calls this event. /// </remarks> private void oc_gotLine(object sender, GotLineEventArgs e) { // drop a line m_logs.logDebugLine(10, "Got: " + e.line); string s = e.line; // some lines start with a ">" (see link above) // they come asynchron and are parsed imediately if (s.StartsWith(">")) { string type = s.Substring(1, s.IndexOf(":") - 1); string msg = s.Substring(type.Length + 2); string[] infos = null; AsyncEventDetail.EventType et = AsyncEventDetail.EventType.UNKNOWN; switch (type) { case "ECHO": et = AsyncEventDetail.EventType.ECHO; break; case "FATAL": et = AsyncEventDetail.EventType.FATAL; break; case "HOLD": et = AsyncEventDetail.EventType.HOLD; break; case "INFO": et = AsyncEventDetail.EventType.INFO; break; case "LOG": et = AsyncEventDetail.EventType.LOG; break; case "NEED-STR": et = AsyncEventDetail.EventType.NEEDSTR; string tmp = msg.Substring(msg.IndexOf('\'') + 1); infos = new string[] { tmp.Substring(0, tmp.IndexOf('\'')) }; break; case "STATE": et = AsyncEventDetail.EventType.STATE; infos = msg.Split(new char[] { ',' }); break; case "PASSWORD": et = AsyncEventDetail.EventType.PASSWORD; // Several messages format are possible // * first is a request for a passwd // >PASSWORD:Need 'Auth' username/password // or // >PASSWORD:Need 'Private Key' password // // * second is a notification // >PASSWORD:Verification Failed: 'Auth' // or // >PASSWORD:Verification Failed: 'Private Key' // Let's first determine the PASSWORD message type and thus format string messType = msg.Substring(0, msg.IndexOf(' ')); // "Need" or "Verification" if (messType.CompareTo("Need") == 0) { string tmp2 = msg.Substring(msg.IndexOf('\'') + 1); string loginProfile = tmp2.Substring(0, tmp2.IndexOf('\'')); // 'Auth' or 'Private Key' or ... string loginInfo = tmp2.Substring(tmp2.IndexOf('\'') + 2); // "password" or "username/password" infos = new string[] { loginProfile, loginInfo, messType }; } else if (messType.CompareTo("Verification") == 0) { string verifMsg = msg.Substring(0, msg.IndexOf(':')); // "Verification Failed" if (verifMsg.CompareTo("Verification Failed") == 0) { string tmp2 = msg.Substring(msg.IndexOf('\'') + 1); string loginProfile = tmp2.Substring(0, tmp2.IndexOf('\'')); // 'Auth' or 'Private Key' or ... infos = new string[] { loginProfile, null, verifMsg }; } } break; } if (et != AsyncEventDetail.EventType.UNKNOWN) { m_ol.got_asyncEvent(new AsyncEventDetail(et, msg, infos)); return; } } m_received.Append(s + Environment.NewLine); s = m_received.ToString(); if (s.StartsWith("SUCCESS: ") || s.StartsWith("ERROR: ") || s.StartsWith(">") || s.EndsWith("END" + Environment.NewLine)) { m_received.Remove(0, m_received.Length); m_ol.cb_syncEvent(s); } }
/// <summary> /// Connects to the management interface. /// </summary> public void connect() { m_logs.logLine(OVPNLogEventArgs.LogType.MGNMT, "Connecting to management interface"); m_logs.logDebugLine(1, "Connecting to management interface"); try { m_tcpC.Connect(m_host, m_port); } catch (SocketException e) { m_logs.logDebugLine(1, "Connection failed: " + e.Message); throw; // new ApplicationException("Could not connect to socket: " + e.Message); } m_sread = new StreamReader(m_tcpC.GetStream()); m_swrite = new StreamWriter(m_tcpC.GetStream()); m_reader = new Thread(new ThreadStart(readerThread)); m_reader.Name = "management interface reader thread"; m_reader.Start(); m_connected = true; }
/// <summary> /// We got a synchronous message. /// </summary> /// <param name="msg">The message</param> public void cb_syncEvent(string msg) { // the reaction depends on what we are waiting for switch (m_state) { // the number of SmartCards case WaitState.PKCS11_GET_COUNT: m_pkcs11count = m_ovpnMParser.getPKCS11IDCount(msg); if (m_pkcs11count == -1) { m_logs.logLine(OVPNLogEventArgs.LogType.MGNMT, "Could not determine the number of pkcs11-ids:\"" + msg + "\""); releaseLock(); } else if (m_pkcs11count == 0) { m_logs.logLine(OVPNLogEventArgs.LogType.MGNMT, "No pkcs11-ids were found"); int id = m_ovpn.getKeyID(new List <PKCS11Detail>()); if (id == OVPNNeedCardIDEventArgs.RETRY) { m_ovpnComm.send("pkcs11-id-count"); } else { releaseLock(); } } else { m_logs.logLine(OVPNLogEventArgs.LogType.MGNMT, "Got " + m_pkcs11count + " PKCS11-IDs"); m_pkcs11details.Clear(); releaseLock(); setLock(WaitState.PKCS11_GET_KEYS); m_ovpnComm.send("pkcs11-id-get 0"); } break; case WaitState.PKCS11_GET_KEYS: PKCS11Detail d = m_ovpnMParser.getPKCS11ID(msg); if (d != null) { m_pkcs11details.Add(d); if (d.nr < m_pkcs11count - 1) { m_ovpnComm.send("pkcs11-id-get " + (d.nr + 1)); } else { releaseLock(); int kid = m_ovpn.getKeyID(m_pkcs11details); if (kid == OVPNNeedCardIDEventArgs.RETRY) { setLock(WaitState.PKCS11_GET_COUNT); m_ovpnComm.send("pkcs11-id-count"); } else if (kid != OVPNNeedCardIDEventArgs.NONE) { m_ovpnComm.send("needstr 'pkcs11-id-request' '" + m_pkcs11details[kid].id + "'"); } } } // error in parsing else { m_logs.logDebugLine(1, "Error while parsing pkcs11-id-get: \"" + msg + "\""); releaseLock(); } break; // logging was turned on, wait for log lines case WaitState.LOG_ON_ALL_1: setLock(WaitState.LOG_ON_ALL_2,true); break; // logging was turned on case WaitState.LOG_ON: case WaitState.LOG_ON_ALL_2: releaseLock(); string[] m = msg.Split("\n".ToCharArray()); for (int i = 0; i < m.GetUpperBound(0) - 1; ++i) { addLog(m[i]); } setLock(WaitState.STATE); m_ovpnComm.send("state on"); break; // "state" was set case WaitState.STATE: releaseLock(); if (m_releaselock) { setLock(WaitState.HOLD_RELEASE); m_ovpnComm.send("hold release"); m_releaselock = false; } break; // hold relese was executed case WaitState.HOLD_RELEASE: releaseLock(); break; // we sent a signal case WaitState.SIGNAL: releaseLock(); break; // something else happened (this should not happen) // we release the lock default: releaseLock(); break; } }