Class switchSshSession
Inherits switchSession
Private SSHPasswordConnection As Renci.SshNet.PasswordAuthenticationMethod
Private SSHKeyboardInteractive As Renci.SshNet.KeyboardInteractiveAuthenticationMethod
Private SSHConnectionInfo As Renci.SshNet.ConnectionInfo
Private ClientSsh As Renci.SshNet.SshClient = Nothing
Private SSHShell As Renci.SshNet.Shell = Nothing
Private SSHStream As Renci.SshNet.ShellStream
Private SSHreader As StreamReader
Private SSHwriter As StreamWriter
Public Sub New(scriptText As String, ResponseWait As Integer, ResponseRetries As Integer)
' The switchSshSession New call's base class New to fill ScriptSend and ScriptWait
' and performs the SSH session setup
MyBase.New(scriptText, ResponseWait, ResponseRetries)
ClientPort = 22
Try
' if PasswordAuthentication is requested (demanded) by the switch, we can handle that
SSHPasswordConnection = New Renci.SshNet.PasswordAuthenticationMethod(ClientUsername, ClientPassword)
SSHKeyboardInteractive = New Renci.SshNet.KeyboardInteractiveAuthenticationMethod(ClientUsername)
SSHConnectionInfo = New Renci.SshNet.ConnectionInfo(ClientIP, ClientPort, ClientUsername, SSHPasswordConnection, SSHKeyboardInteractive)
AddHandler SSHKeyboardInteractive.AuthenticationPrompt, AddressOf SSHhandleKeyboardAuthentication
ClientSsh = New Renci.SshNet.SshClient(SSHConnectionInfo)
ClientSsh.ConnectionInfo.Timeout = TimeSpan.FromSeconds(10)
ClientSsh.ConnectionInfo.RetryAttempts = 3
ClientSsh.Connect()
If ClientSsh.IsConnected = False Then
Throw New Exception("connection failed")
Exit Sub
End If
SSHStream = ClientSsh.CreateShellStream("xterm", 80, 24, 800, 600, 1024)
SSHreader = New StreamReader(SSHStream)
SSHwriter = New StreamWriter(SSHStream)
SSHwriter.AutoFlush = True
Thread.Sleep(ClientResponseWait)
SSHreader.ReadToEnd()
Catch ex As Exception
sessionStatus = ex.Message & " connecting " & ClientIP & " port " & ClientPort & " (SSH)"
ClientValid = False
End Try
End Sub
Public Overloads Function ExecuteScript() As Boolean
' perform SSH i/o
'
' In the While loop the commands in ScriptSend are send and responses in ScriptWait are
' (substring) matched to the received response.
' SSHReadResult does the actual reading.
' The ClientResponse is build up as we go along, replacing passwords with *******
ExecuteScript = False
Dim sendString As String = ""
Dim waitString As String = ""
Dim receivedString As String = ""
Dim PasswordSkip As Boolean = False
sessionIOindex = 3 ' ssh offset 3: 0 = ip, 1 = username, 2 = password
Try
While sessionIOindex < ScriptSend.Length
sendString = ScriptSend(sessionIOindex)
waitString = ScriptWait(sessionIOindex)
SSHStream.Write(sendString & vbCr) ' send command
receivedString = SSHReadResult(waitString) ' read result
If receivedString.IndexOf(waitString, 0, receivedString.Length, StringComparison.CurrentCultureIgnoreCase) < 0 Then
Throw New Exception("received: '" & receivedString & "' waiting for: '" & waitString & "'")
End If
If PasswordSkip Then
ClientResponse += "*******"
Else
ClientResponse += receivedString
End If
ClientResponse += Environment.NewLine
PasswordSkip = False
If receivedString.IndexOf("password", 0, receivedString.Length, StringComparison.CurrentCultureIgnoreCase) >= 0 Then
PasswordSkip = True
End If
sessionIOindex += 1
End While
ExecuteScript = True
Catch ex As Exception
sessionStatus = ex.Message & Environment.NewLine & "send [ " & sendString & _
" ] to " & ClientIP & " (SSH), expecting response to contain [ " & waitString & " ] (script-index " & sessionIOindex * 2 & ")"
ExecuteScript = False
End Try
End Function
Private Sub SSHhandleKeyboardAuthentication(sender As Object, e As Renci.SshNet.Common.AuthenticationPromptEventArgs)
For Each prompt As Renci.SshNet.Common.AuthenticationPrompt In e.Prompts
If prompt.Request.Equals("Password: ", StringComparison.InvariantCultureIgnoreCase) Then
prompt.Response = ClientPassword
End If
Next
End Sub
Private Function SSHReadResult(Expected As String) As String
' Read the result from SSHreader until Expected is read.
' Commands issued to the switch may require some processing. Not all data may be available at once, so give em some slack.
' We asume the command send to allways be received by the switch
Dim strRead As String = ""
Dim retries As Integer = 0
Try
Thread.Sleep(ClientResponseWait) ' give IOS a first change to form the response
strRead = SSHreader.ReadToEnd
While retries < ClientResponseRetries
If strRead.IndexOf(Expected, 0, strRead.Length, StringComparison.CurrentCultureIgnoreCase) < 0 Then
retries += 1
Thread.Sleep(ClientResponseWait)
If SSHStream.DataAvailable Then
strRead += SSHreader.ReadToEnd ' append to data already received
End If
Else
Exit While
End If
End While
Return (strRead)
Catch ex As Exception
Return (Nothing)
End Try
End Function
Public Overloads Sub Dispose()
MyBase.Dispose()
On Error Resume Next
SSHreader.Close()
SSHreader.Dispose()
SSHwriter.Close()
SSHwriter.Dispose()
SSHShell.Dispose()
Err.Clear()
End Sub
End Class
Many thanks to the Renci SSH.NET developers!Regards, Paul