telnetをネストしてファイルを取得するには?

解決


かわい  2006-09-27 05:10:34  No: 96737

お世話になっております。

環境は、Windows XP(Or Windows 2000)、
VB6.0 SP6 + BASP21をインストールした端末で開発・運用をしています。

過去ログを調べ、遠隔サーバにあるファイルをFTPで取得する為には
BASP21を使うと開発が楽という記事を見かけました。

しかし、Telnetを複数回ネスト
(telnetにログインした後別のサーバにtelnetログインする)といった方法や
telnetにログインした後別のサーバにFTPでログイン、ファイルを取得する。という処理を行う場合等のサンプルは得られませんでした。

っとすると、
VB6.0で、telnetを複数ネストした処理を行う場合などは
GUI画面上で入力された情報から、batファイルを出力し、
実行させる方法しか思いつかないのですが、
途中経過の表等が出来ないなどの問題がある為、
出来れば他の方法を取りたいのですが、
こういった処理を行うことはVBでは無理なのでしょうか?

参考となる情報がありましたら、些細なことでもかまいませんので
返信いただきたいと思います。


ヤマ@文系  2006-09-27 23:31:53  No: 96738

telnetで接続できるサーバに接続してそこからFTPでいきたいということなのでしょうか。
サーバ自体そもそも外部へアクセスが許可されているならwinsockを使えばできるはずですが
>VB6.0で、telnetを複数ネストした処理を行う場合などは
>GUI画面上で入力された情報から、batファイルを出力し、
>実行させる方法しか思いつかないのですが、
ここらへんの処理を書いておかれると
みなさん返答しやすいかとおもいます。


かわい  2006-09-28 01:14:11  No: 96739

>telnetで接続できるサーバに接続してそこからFTPでいきたいということなのでしょうか。

はい、イメージでは
Winows端末(Windows) - 中間サーバA - 中間サーバB - 装置A(Linux)
となり、FTPサービス、Telnetサービスが起動しています。

最終的な目標は、装置Aからログファイルを取得する。
ですが、その装置Aは操作端末(Windows XP)から直接FTPで覗くことは出来なく中間サーバを経由(telnet・FTPで)する必要があります。


かわい  2006-09-28 01:30:16  No: 96740

昨日、私の考えていた
>GUI画面上で入力された情報から、batファイルを出力し、
というのは、
Windows標準で搭載されているコマンドプロンプトから

  c:\ >telnet 127.0.0.1[=IP-Address] と入力すると、

「Microsoft Telnetクライアント」が起動しますが、
これを利用し、VBから、Telnet接続、FTP処理できないか?
と考えてました。
コマンドプロンプトで出来るならば、
Batファイルでも出来るのではないか?という安直な意識がありました。

現在の進捗としましては、
Batファイル化(※)したのですが、TelNet...の処理を実行後(1)、
手動でExitするまで次の処理(2)を受け付けないのが解り、早くも
Batファイルを利用しての接続をあきらめなければいけないのか?
っと思っているところです。
(telnet /? などを調べてもヘルプサポートされていないため)

(※)バッチファイルの中身
  Call Telnet 127.0.0.1  ・・・(1)
  Call USERNAME          ・・・(2)
  Call PASSWORD


かわい  2006-09-28 01:35:53  No: 96741

長々と申し訳ないです。

Batファイルでダメ(見切りが早いかもしれませんが)ならば、
代わりにテラタームマクロ(.ttl)を利用し、
同じこと(TELNET・FTPの処理を任せてしまう)が出来ないか?は、
今試行錯誤中のため、その結果は今は出せていないです。


ヤマ@文系  2006-09-28 03:53:49  No: 96742

中間サーバが二つあるので
カスケード接続ができないとダメなんではないでしょうか?

ひとつであれば、過去ログかなんかにないでしょうか?
winsockのconnectedあたりでプロトコルにあった処理をするような。

中間A->中間B
というのがセキュリティ的に?な感じです。

'参考資料
RFC 854
RFC 959


かわい  2006-09-28 05:51:17  No: 96743

ヤマ@文系 さん 再びのアドバイス、本当にありがとうございます。

Winsockコントロールは使ったことがなかったので、
何とか楽する
(コマンドプロンプトやテラタームのウィンドウハンドル?を
取ってメッセージの送信で簡潔させるetc)ようと考えていましたが・・・。

まずは慌てず、一歩一歩、
Winsockコントロールの使用例と紹介いただいた、
RFCをググりながらちょっとづつ進めていこうかと思います。


ヤマ@文系  2006-09-28 07:38:53  No: 96744

こちらもwinsockとか書いてしまいましたが、
inetコントロール(wininet)だとproxyを超えられない可能性があります。

http://support.microsoft.com/default.aspx?scid=kb;ja;409931


あん  2006-09-28 10:41:21  No: 96745

telnetの標準入出力がとれればいいのですが・・

とれないのは
セキュリティを考えてなのかも
しれませんね


かわい  2006-09-28 11:58:41  No: 96746

ヤマ@文系 さん、あん さん夜分に恐れ入ります
今はテラタームを使って人が
手打ちでコマンドを入力し、ログ取得をしており
ツール化出来ないか?
という要望のため、全く意識出来て無かったですが
プロキシの件は要考慮ですね。
ご指摘ありがとうございます。

社内で仮の中間サーバを用意して
検討(動かしながら調査)している段階ですので実際は
プロキシサーバ越えの検討は後回しになってしまうかもしれませんが・・・。

2重のテルネットが可能か?を優先しているため
今週末までもう少し調査しながらハマってみます。

サンプルソースなど示せず申し訳有りません。
ちょこちょこ悩みながらなので掲示できるレベルのもの
になれば掲示します。


かわい  2006-09-30 05:43:47  No: 96747

お世話になっております。

貴重なアドバイスを元に、2重テルネットの実装が出来ましたので、
後学のためになるか解らないのですが、フィードバックいたします。

前準備'フォームモジュールに
テキストボックス 4つ
コマンドボタン 2つ
Winsockコントロール 1つ貼り付けます。

'===以下ソースコード
Private Sub Command1_Click()
    
    With Winsock1
        If .State = sckClosed Then
            .RemoteHost = Text1.Text        ' 接続ホスト名
            .RemotePort = Text2.Text        ' 接続ポート番号
            .Protocol = sckTCPProtocol      ' 接続プロトコル
            .Connect
        End If
    End With
End Sub
Private Sub Winsock1_Connect()
    
    MsgBox "接続しました" & vbCrLf & _
           Winsock1.RemoteHost & vbCrLf & _
           Winsock1.RemotePort

    Do
        Call Wait
        If telnetInfo_flg = True Then
            Exit Do
        End If
        Call SetTelnetOption
    Loop
    Call TelnetLogin
    
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    
    Dim LngCnt As Long               ' 汎用カウンタ
    
    Text3.Text = ""
    ReceveInfo_flg = True
    
    ' データの受信
    ReDim bytReceiveData(bytesTotal - 1)
    
    Winsock1.GetData bytReceiveData, vbArray + vbByte, bytesTotal
    For LngCnt = 0 To UBound(bytReceiveData)
        Text5.Text = Text5.Text & "," & Hex(bytReceiveData(LngCnt))
    Next LngCnt
    Debug.Print "ReservData:" & Text5.Text
    
    ReceveInfo_flg = False

End Sub

Public Function Wait() As Boolean

    Do
        DoEvents
        Sleep 500                       ' 500ミリ秒処理をとめる
        
        If ReceveInfo_flg = False Then  ' 受信待ちになったら処理を抜ける
            Exit Do
        
        ElseIf Winsock1.State = sckClosed Then
            Exit Do
        
        End If
    Loop
    
End Function
Public Sub SetTelnetOption()

    Dim LngCnt As Long               ' 汎用カウンタ
    Dim bytLogin(6) As Byte          ' login: プロンプト
    
    ' login: 表示されているか確認
    bytLogin(0) = &H6C  ' [l]
    bytLogin(1) = &H6F  ' [o]
    bytLogin(2) = &H67  ' [g]
    bytLogin(3) = &H69  ' [i]
    bytLogin(4) = &H6E  ' [n]
    bytLogin(5) = &H3A  ' [:]
    
    For LngCnt = 0 To UBound(bytReceiveData) - 6
        If (bytReceiveData(LngCnt) = bytLogin(0)) And _
            (bytReceiveData(LngCnt + 1) = bytLogin(1)) And _
            (bytReceiveData(LngCnt + 2) = bytLogin(2)) And _
            (bytReceiveData(LngCnt + 3) = bytLogin(3)) And _
            (bytReceiveData(LngCnt + 4) = bytLogin(4)) And _
            (bytReceiveData(LngCnt + 5) = bytLogin(5)) Then
                telnetInfo_flg = True
                Exit Sub
        End If
    Next LngCnt
    
    Erase bytSendData
    ReDim bytSendData(UBound(bytReceiveData))
    LngCnt = 0
    
    ' データの送信
    Do
        
        bytSendData(LngCnt) = bytReceiveData(LngCnt)
        If (LngCnt > UBound(bytReceiveData) - 1) Then Exit Do
        
        If bytReceiveData(LngCnt) = OPT_COM Then
        
            ' http://www5e.biglobe.ne.jp/~aji/3min/55.html 参考
            Select Case bytReceiveData(LngCnt + 1)
           
            Case OPT_DO      ' 相手にオプション使用を要求
                bytSendData(LngCnt + 1) = OPT_WONT   ' オプションを使用しない
           
            Case OPT_WILL    ' 自分がオプション使用を宣言
                bytSendData(LngCnt + 1) = OPT_DONT   ' オプションを許可しない
           
            Case OPT_WONT    ' 相手のオプション使用をやめさせる
                bytSendData(LngCnt + 1) = OPT_WONT   ' 自身のオプションを無効にする
           
            Case OPT_DONT    ' 自分のオプションの無効化を宣言
                bytSendData(LngCnt + 1) = OPT_DONT   ' 了解する
           
            Case Else
                bytSendData(LngCnt + 1) = bytReceiveData(LngCnt + 1)
           
            End Select
            LngCnt = LngCnt + 1
        End If
        LngCnt = LngCnt + 1
   
    Loop
        
    Winsock1.SendData bytSendData
    Erase bytSendData

End Sub
Public Sub TelnetLogin()
    
    Dim bytEcho(2) As Byte          '
    
    bytEcho(0) = &HFF                           ' Do ECHO
    bytEcho(1) = &HFC
    bytEcho(2) = &H1
    Winsock1.SendData bytEcho
    Call Wait
    
    bytEcho(0) = &HFF                           ' WONT ECHO
    bytEcho(1) = &HFE
    bytEcho(2) = &H1
    Winsock1.SendData bytEcho
    Call Wait
    
    Winsock1.SendData "kawai" & vbCrLf        ' 中間サーバA ユーザID
    Call Wait
    
    Winsock1.SendData "kawai" & vbCrLf        ' 中間サーバA パスワード
    Call Wait
    
    Winsock1.SendData "pwd" & vbCrLf            ' コマンド発行
    Call Wait
        
    Winsock1.SendData "telnet IP-ADDRESS" & vbCrLf    ' 2重テルネット開始
    Call Wait
    Call Wait
    
    Winsock1.SendData "user" & vbCrLf                 ' 中間サーバB ユーザID
    Call Wait
    Call Wait
    
    Winsock1.SendData "pass" & vbCrLf                  ' 中間サーバB パスワード
        
End Sub


かわい  2006-09-30 05:44:37  No: 96748

'続いて標準モジュール

Option Explicit

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

' TELNET Command 定数

Public Const OPT_WILL As Byte = &HFB    ' OPTION CODE( WILL )
Public Const OPT_WONT As Byte = &HFC    ' OPTION CODE( WON'T )
Public Const OPT_DO As Byte = &HFD      ' OPTION CODE( WILL )
Public Const OPT_DONT As Byte = &HFE    ' OPTION CODE( WON'T )
Public Const OPT_COM As Byte = &HFF     ' [Interpret as Command] コマンドとして解釈

Public bytReceiveData() As Byte
Public bytSendData() As Byte

です。


かわい  2006-09-30 05:52:44  No: 96749

苦労した点ですが、
接続完了した
Private Sub Winsock1_Connect()
で接続の後に、すぐloginが表示されるか?というとそうではないことが
解り、様々なオプションを設定してやらないといけないようです。

この情報は、ヤマ@文系 さんから提供いただいたRFC、及び
http://www5e.biglobe.ne.jp/~aji/3min/55.htmlのサイトが参考
となりました。

上記ソースでは、全てのオプションを無効にして接続するよう
設定を行っています。

ただし、一つ目のテルネットが完了した後、
2つ目のテルネットはコマンド発行のみ
Winsock1.SendData "telnet IP-ADDRESS" & vbCrLf    ' 2重テルネット開始

で住みました、おそらくですが、ftpも同様の手法で接続できるはずです。

また、あん さんが懸念しておりました。
テルネットでの応答内容の取得も、pwdコマンド発行のレスが
受信できました。

最後に。。。
このスレッドにアドバイスしていただいた皆様
また、返信いただかなくとも興味を持っていただいた皆様に感謝し
スレッドを閉じたいと思います。

ありがとうございました。


かわい  2006-09-30 05:53:12  No: 96750

解決チェックがもれていました。


ヤマ@文系  2006-10-01 00:52:06  No: 96751

解決できてよかったですね!
SendData "telnet "
というところがミソですね。


あん  2006-10-01 01:11:21  No: 96752

感動しました!
このロジック使えます!
標準入出力できる対話型telnet作ってみようかな
そうすればvbsとかで自動実行できそうだ


かわい  2006-10-01 06:10:54  No: 96753

>SendData "telnet "
>というところがミソですね。

はい、あのあと同様に
SendData "ftp "とやっても
ftp>
が帰ってきたのでftpも問題有りませんでした。

>感動しました!
>このロジック使えます!

あとはもう少し次のコマンド発行まで
時間指定ではなく応答メッセージを解析する。
テルネットオプションの設定を柔軟にする
など改良が必要ですが、実現できるか?
の検証を優先させたため、かなりこの部分は適当で恥ずかしいサンプルすが、。

あんさん やま@文系さんありがとうございます。


あん  2006-10-03 16:46:22  No: 96754

対話型のtelnet作ってみました  VB.NET版です

Imports System.io
Imports System.Net
Imports System.Net.Sockets

Public Class TelnetClient

    Public Const OPT_WILL As Byte = &HFB    ' OPTION CODE( WILL )
    Public Const OPT_WONT As Byte = &HFC    ' OPTION CODE( WON'T )
    Public Const OPT_DO As Byte = &HFD      ' OPTION CODE( WILL )
    Public Const OPT_DONT As Byte = &HFE    ' OPTION CODE( WON'T )
    Public Const OPT_COM As Byte = &HFF     ' [Interpret as Command] コマンドとして解釈

    Private _addr As String
    Private _port As String
    Private _user As String
    Private _pass As String
    Private _client As TcpClient
    Private _ns As NetworkStream
    Private _reader As BinaryReader
    Private _writer As BinaryWriter

    Public Sub New(ByVal addr, Optional ByVal port = 23)
        _addr = addr
        _port = port
    End Sub

    Public Sub Open()
        _client = New TcpClient(_addr, _port)
        _ns = _client.GetStream
        _client.ReceiveTimeout = 100
    End Sub

    Public Sub Read(ByRef str As String)
        Dim data() As Byte
        Dim echo1() As Byte = {&HFF, &HFC, &H1}
        Dim echo2() As Byte = {&HFF, &HFE, &H1}
        Try
            Read(data)
            str = System.Text.Encoding.GetEncoding("Shift_JIS").GetString(data)
            If str Like "*login*" Then
                Write(echo1)
                Write(echo2)
            End If
        Catch ex As Exception
            Throw New ApplicationException("")
        End Try
    End Sub

    Public Sub Read(ByRef data As Byte())
        _reader = New BinaryReader(_ns)
        _writer = New BinaryWriter(_ns)
        Dim msi As New MemoryStream
        Dim mso As New MemoryStream
        Dim dat As Byte

        Try
            Do
                dat = _reader.ReadByte
                msi.WriteByte(dat)
                mso.WriteByte(dat)
                If dat = OPT_COM Then
                    dat = _reader.ReadByte
                    msi.WriteByte(dat)
                    Select Case dat

                        Case OPT_DO      ' 相手にオプション使用を要求
                            mso.WriteByte(OPT_WONT)   ' オプションを使用しない
                        Case OPT_WILL    ' 自分がオプション使用を宣言
                            mso.WriteByte(OPT_DONT)   ' オプションを許可しない
                        Case OPT_WONT    ' 相手のオプション使用をやめさせる
                            mso.WriteByte(OPT_WONT)   ' 自身のオプションを無効にする
                        Case OPT_DONT    ' 自分のオプションの無効化を宣言
                            mso.WriteByte(OPT_DONT)   ' 了解する
                        Case Else
                            mso.WriteByte(dat)
                    End Select
                End If
            Loop
        Catch ex As System.Net.Sockets.SocketException
            Debug.WriteLine(ex.ToString)
            Throw New ApplicationException("")
        Catch ex As System.IO.EndOfStreamException
            Debug.WriteLine(ex.ToString)
            Throw New ApplicationException("")
        Catch ex As Exception
            Debug.WriteLine(ex.ToString)
        End Try
        If mso.ToArray.Length > 0 AndAlso mso.ToArray.GetValue(0) = &HFF Then
            Debug.WriteLine("mso = " & BitConverter.ToString(mso.ToArray))
            _writer.Write(mso.ToArray)
            _writer.Flush()
        End If
        If msi.ToArray.Length > 0 Then
            Debug.WriteLine("msi = " & BitConverter.ToString(msi.ToArray))
        End If
        data = msi.ToArray
    End Sub

    Public Sub Write(ByVal str As String)
        Dim data() As Byte
        Dim echo1() As Byte = {&HFF, &HFC, &H1}
        Dim echo2() As Byte = {&HFF, &HFE, &H1}

        data = System.Text.Encoding.GetEncoding("Shift_JIS").GetBytes(str)
        Write(data)
    End Sub

    Public Sub Write(ByVal data As Byte())
        _writer = New BinaryWriter(_ns)
        Dim mso As New MemoryStream

        Try
            mso.Write(data, 0, data.Length)
            _writer.Write(mso.ToArray)
            _writer.Flush()
        Catch ex As System.Net.Sockets.SocketException
            Debug.WriteLine(ex.ToString)
            Throw New ApplicationException("")
        Catch ex As System.IO.EndOfStreamException
            Debug.WriteLine(ex.ToString)
            Throw New ApplicationException("")
        Catch ex As Exception

        End Try
    End Sub

End Class


あん  2006-10-03 16:48:25  No: 96755

続きです  メイン

Module Module1

    Sub Main()
        Dim tel As New TelnetClient(System.Environment.GetCommandLineArgs(1))
        Dim data As Byte()
        Dim str As String
        Dim stro As String
        Dim flg As Boolean = False
        Try
            tel.Open()
            Do
                tel.Read(str)
                Debug.WriteLine(str)
                Console.Write(str)
                stro = Console.ReadLine()
                If stro <> "" Then
                    tel.Write(stro & vbCrLf)
                End If
            Loop
        Catch ex As Exception
        End Try

    End Sub

End Module


かわい  2006-10-03 17:55:14  No: 96756

短時間で、流石です。


あん  2006-10-03 22:19:09  No: 96757

対話型telnetを使用したVBScriptの例

Set objShell = WScript.CreateObject("WScript.Shell")
Set objExec = objShell.Exec("TelnetClient.exe localhost")

Do Until objExec.StdOut.AtEndOfStream     
  strLine = objExec.StdOut.ReadLine()
  Wscript.StdOut.WriteLine strLine
  If InStr(strLine,"login:") <> 0 Then    
    objExec.StdIn.WriteLine "user"
    Wscript.StdOut.WriteLine "Administrator"
    input = ""
  Else 
    If InStr(strLine,"password:") <> 0 Then    
      objExec.StdIn.WriteLine "pass"
      Wscript.StdOut.WriteLine"pass"
    Else
      If InStr(strLine,">") <> 0 and flg = 0 Then 
        objExec.StdIn.WriteLine "Dir" 
        Wscript.StdOut.WriteLine "Dir" 
        objExec.StdIn.WriteLine "exit"
        Wscript.StdOut.WriteLine "exit"
        flg = 1
      Else
        objExec.StdIn.WriteLine ""
      End If
    End If
  End If
Loop

入出力を楽にするためメインちと修正・・

Module Module1

    Sub Main()
        Dim tel As New TelnetClient(System.Environment.GetCommandLineArgs(1))
        Dim data As Byte()
        Dim str As String
        Dim stro As String
        Dim flg As Boolean = False
        Try
            tel.Open()
            Do
                tel.Read(str)
                Debug.WriteLine(str)
                Console.WriteLine(str) 'ここ
                stro = Console.ReadLine()
                If stro <> "" Then
                    tel.Write(stro & vbCrLf)
                End If
            Loop
        Catch ex As Exception
        End Try

    End Sub

End Module


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加