简体   繁体   English

如何以编程方式telnet并通过TCP套接字发出命令?

[英]How to telnet programmatically and issue commands via a TCP socket?

I am working on an application in C for an embedded Linux system on a serial device server. 我正在C中为串行设备服务器上的嵌入式Linux系统开发应用程序。 I need to access the system's own shell that you can telnet to and has a bunch of custom command line interface commands that can be executed at the shell prompt. 我需要访问系统自己的shell,你可以telnet到它,并有一堆自定义命令行界面命令,可以在shell提示符下执行。

An engineer working for the manufacturer of the device said the only way to programatically issue these command line interface commands is via a telnet client that logs into the shell. 为该设备制造商工作的工程师说,以编程方式发出这些命令行界面命令的唯一方法是通过登录到shell的telnet客户端。

So, within my application, I want to have the device server telnet to itself so that it can issue some commands to itself via its shell. 因此,在我的应用程序中,我想让设备服务器telnet自己,以便它可以通过它的shell向自己发出一些命令。 Before I do the C implementation, I figured I'd just try to open a socket via IRB and try to get the commands working that way first. 在我执行C实现之前,我想我只是尝试通过IRB打开一个套接字并尝试首先以这种方式运行命令。 The actual telnet session looks like this: 实际的telnet会话如下所示:

login: admin
password: password

prompt# set watchdog off
prompt# save
Save config to flash ROM y/n
y    

Below is the simple script I'm running in IRB to see if I can emulate the above telnet session via a TCP socket since that's how I'll implement in C on Linux: 下面是我在IRB中运行的简单脚本,看看我是否可以通过TCP套接字模拟上述telnet会话,因为这是我在Linux上用C实现的方式:

require 'socket'
@ip = 'xxx.xxx.xxx.xxx'
@enter = "\n"
@sock = TCPSocket.open(@ip,23)
@ret = @sock.write("admin" + @enter)
puts @ret.to_s
sleep(1)      
@ret = @sock.write("password" + @enter)
puts @ret.to_s
puts @sock.read(1)
sleep(2)
@ret = @sock.write("set watchdog off" + @enter)
puts @ret.to_s
puts @sock.read(1)
sleep(1)
@ret = @sock.write("save" + @enter)
puts @ret.to_s
puts @sock.read(1)
sleep(1)
@ret = @sock.write("y")
puts @ret.to_s
puts @sock.read(1)
sleep(1)

@sock.close

Opening, writing to and reading from sockets in C are no problem for me and I do it a lot already in my application so I already have easy functions to do those things ready to go. 打开,写入和读取C中的套接字对我来说没有问题,而且我已经在我的应用程序中做了很多,所以我已经有了很容易的功能来做好准备好的事情。 My question is what strings should I be writing to the sockets to emulate let's say pressing the enter key after I type something at a prompt? 我的问题是我应该写什么字符串来模拟套接字让我说在输入提示符后输入回车键? "\\n" or "\\x0a" were not working. “\\ n”或“\\ x0a”无效。 OR could I be using a linux C library that'll make this way easier for me? 或者我可以使用Linux C库,这会让我更容易吗?

You could definitely go read the telnet protocol, but check out the answer at the bottom of the link below that involves using WireShark to actually see what's flying back and forth. 你绝对可以阅读telnet协议,但请查看下面链接底部的答案,其中涉及使用WireShark实际查看来回飞行的内容。

http://www.codeproject.com/Questions/147555/Telnet-client-using-TCP http://www.codeproject.com/Questions/147555/Telnet-client-using-TCP

If you've never used a packet sniffer, it's very enlightening (as it was for me). 如果你从来没有使用过数据包嗅探器,那就非常有启发性(就像我一样)。 Here are the steps I followed to telnet over a TCP socket connection. 以下是我通过TCP套接字连接telnet的步骤。

(1) Follow the directions at the above link to capture the traffic on your network while you execute exactly the commands you want to eventually execute with your desired application/script beginning with creating the telnet connection and ending with closing it (1)按照上述链接中的说明捕获网络上的流量,同时执行您希望最终使用所需应用程序/脚本执行的命令,从创建telnet连接开始,最后关闭它

(2) After you stop capturing your session, you might see in your capture a lot of other traffic that was happening on your network at the same time, so filter that out with ip.addr == xxx.xxx.xxx.xxx where you of course use the ip address of the remote computer (2)在您停止捕获会话后,您可能会在捕获中看到网络上同时发生的大量其他流量,因此请使用ip.addr == xxx.xxx.xxx.xxx进行过滤。你当然使用远程计算机的IP地址

(3) Now as you look at all of the stuff going back and forth between your computer and the remote computer, you can see how the application separates out the different layers of communication for each message. (3)现在,当您查看计算机和远程计算机之间来回的所有内容时,您可以看到应用程序如何为每条消息分离出不同的通信层。 You want to pay special attention to the messages with protocol "Telnet", which just means that's the highest layer. 您希望特别注意使用协议“Telnet”的消息,这意味着它是最高层。 When you highlight a message on the topmost pane of the WireShark window, you see in the second pane down how it separates that message into its different layers. 当您在WireShark窗口的最顶部窗格中突出显示一条消息时,您会在第二个窗格中看到它如何将该消息分成不同的层。 In that second pane, if you highlight let's say the Telnet layer, you can see how in the third pane down, the bytes of the message that implement the telnet protocol become highlighted. 在第二个窗格中,如果您突出显示让我们说Telnet层,您可以看到如何在第三个窗格中向下突出显示实现telnet协议的消息的字节。 Take some time to analyze the messages that are going back forth. 花一些时间来分析正在发回的消息。 You can see in a much more immediate way, the negotiation process involved in the beginning of a telnet communication. 您可以更直接地看到telnet通信开始时涉及的协商过程。

(4) Now you just want to basically emulate the communication you can see in Wireshark in your application. (4)现在您只想基本上模拟您在应用程序中可以在Wireshark中看到的通信。 Remember since you are opening a TCP socket in your application, your application is taking care of all the TCP and down communication stuff behind the scenes, so you only have to worry about reading/writing the telnet bytes/data/commands to your TCP socket. 请记住,因为您在应用程序中打开TCP套接字,您的应用程序正在处理幕后的所有TCP和向下通信,因此您只需要担心将telnet字节/数据/命令读/写到TCP套接字。

This method doesn't take very long at all and doesn't require any extra stuff on your system which is great if you are dealing with a device with limited system resources/a very simple os/no os at all. 这种方法根本不需要很长时间,并且不需要系统上任何额外的东西,如果你正在处理系统资源有限的设备/非常简单的操作系统/无操作系统,这是很好的。 For example the mini Linux system on my device doesn't have Expect already installed, nor does it have an easy way of installing stuff in general. 例如,我的设备上的迷你Linux系统没有安装Expect,也没有简单的方法来安装东西。 I mean it can be done, but we're talking really annoying stuff here. 我的意思是它可以完成,但我们在这里谈论的确很烦人。 Also even if there was a not too crazy way of installing stuff on the box, I already have 50 of these in the field which i already have set to autoupdate to whatever new binary I put on my server sure, but they are not expecting to have to also download a script from my server. 即使有一个不太疯狂的方式在盒子上安装东西,我已经有50个这样的字段,我已经设置自动更新到我放在我的服务器上的任何新二进制肯定,但他们不期望还必须从我的服务器下载脚本。 And again, they don't have an OS installed that would allow them to run that script. 而且,他们没有安装允许他们运行该脚本的操作系统。 So we are talking relatively low level stuff here where keeping it simple is not an option but a requirement. 所以我们在这里谈论相对较低级别的东西,保持简单不是一个选择,而是一个要求。 My final C function that let my serial device server telnet to itself (the only way to access its own command line interface--that's the manufacturer's choice) and issue itself the necessary commands looks like this: 我的最终C函数让我的串行设备服务器telnet自己(访问自己的命令行界面的唯一方法 - 这是制造商的选择)并向自己发出必要的命令如下所示:

turnoff_watchdog
{
  // telnetsock, TCP socket to 127.0.0.1 at port 23, has already been set previously

  char negotiation_1[] = {0xFF,0xFC,0X18,0xFF,0xFC,0x20,0xFF,0xFC,0x23,0xFF,0xFC,0x27,0xFF,0xFD,0x03};
  char negotiation_2[] = {0xFF,0xFC,0x01,0xFF,0xFC,0x1F,0xFF,0xFE,0x05,0xFF,0xFB,0x21};
  char telnet_login_name[] = "admin\r\n";
  char telnet_login_password[] = "password\r\n";
  char set_command[] = "set watchdog off\r\n";
  char save_command[] = "save\r\n";
  char confirm[] = "y\n";
  char escape[] = {0x5E,0x5D,0x0A}; // ^]
  char quit[] = "quit\n";

  sleep(2);
  write(telnetsock,&negotiation_1[0],15);
  sleep(2);
  write(telnetsock,&negotiation_2[0],12);
  sleep(2);
  write(telnetsock,&telnet_login_name[0],7);
  sleep(2);
  write(telnetsock,&telnet_login_password[0],10);
  sleep(2);
  write(telnetsock,&set_command[0],18);
  sleep(2);
  write(telnetsock,&save_command[0],6);
  sleep(2);
  write(telnetsock,&confirm[0],2);
  sleep(2);
  write(telnetsock,&escape[0],3);
  sleep(2);
  write(telnetsock,&quit[0],5);
  sleep(2);

  return(0);
}

Simple as that. 就那么简单。 The most difficult part of this was that the original (what I captured using Wireshark) telnet negotiations were quite a bit longer, but after looking at the options that were being negotiated, I realized I didn't need most of it, so I chopped that down considerably. 最困难的部分是原来(我使用Wireshark捕获的)telnet谈判相当长,但在查看正在谈判的选项后,我意识到我不需要大部分,所以我切碎了这大大减少了。 By the way, if you are intimidated by looking at bytes, don't be. 顺便说一下,如果你被查看字节吓到了,那就不要了。 It's not a big deal. 没什么大不了的。 You see how in negotiation_1 and negotiation_2 above, 0xFF keeps popping up every 3 bytes? 你看到如何在negotiation_1negotiation_2上面,0xFF每隔3个字节一次弹出? Well all those two negotiations are are strings of commands/negotiations each 3 bytes in length starting with 0xFF, trying to communicate what it will and won't do during the telnet session. 那么这两个谈判都是命令/协商的串,每个3字节长度从0xFF开始,尝试传达它在telnet会话期间将会做什么和不会做什么。 And the second byte in each chunk of 3 bytes (either 0xFB, 0xFC, 0xFD or 0xFE) is just communicating whether it WILL or WON'T do something or whether it wants the other guy to DO or DON'T something. 并且每个3字节块(0xFB,0xFC,0xFD或0xFE)中的第二个字节只是在沟通是否会做或不做某事或者是否希望其他人做或不做某事。 The last byte is just the option each is willing or not willing to do or going to do or not do. 最后一个字节只是每个人愿意或不愿意做或不做或不做的选择。 You'll see it in Wireshark how it all gets broken down. 你会在Wireshark中看到它如何分解。 It's actually pretty funny the language of it. 它的语言实际上非常有趣。 I didn't include the lines I originally had where I was reading the socket to see the responses to the negotiations (which I had done all that testing and stuff in ruby since I could just run it in irb super easy), but you must do that and basically just negotiate as little as you can until you get sent the login prompt and then as you can see it's super straightforward. 我没有包括我最初在读取套接字的地方的行,以查看对协商的响应(我已经完成了所有测试和ruby中的东西,因为我可以在irb中轻松地运行它),但是你必须这样做,基本上只是尽可能少地协商,直到你收到登录提示,然后你可以看到它超级直接。 Make sure in testing to determine the first negotiation you will write to the socket, that when you open the socket, you read in whatever telnet control sequences are sent FIRST. 确保在测试中确定您将写入套接字的第一个协商,当您打开套接字时,您将读取所有telnet控制序列首先发送的内容。 Then you only want to respond to those sequences--mostly in the negative to reduce the amount of negotiation. 然后你只想回应那些序列 - 主要是否定的,以减少谈判的数量。 Have fun! 玩得开心!

You ask a C question yet you post script, if you want to know how telnet works, read the RFC. 如果你想知道telnet如何工作,你问一个C问题你发布脚本,阅读RFC。 In this case 854 在这种情况下854

http://tools.ietf.org/html/rfc854 http://tools.ietf.org/html/rfc854

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM