HI,
I have a device that exposes a telnet interface which you can log into using a username and password and then manipulate the working of the device.
I have to write a C program that hides the telnet aspect from the client and instead provides an interface for the user to control the device.
What would be a good way to proceed. I tried writing a simple socket program but it stops at the login prompt. My guess is that i am not following the TCP protocol.
Has anyone attempted this, is there an opensource library out there to do this?
Thanks
Addition:
Eventually i wish to expose it through a web api/webservice. The platform is linux.
If Python is an option you could use telnetlib.
Code example:
#!/usr/bin/env python
import getpass
import sys
import telnetlib
HOST = "localhost"
user = raw_input("Enter your remote account: ")
password = getpass.getpass()
tn = telnetlib.Telnet(HOST)
tn.read_until("login: ")
tn.write(user + "\n")
if password:
tn.read_until("Password: ")
tn.write(password + "\n")
tn.write("ls\n")
tn.write("exit\n")
print tn.read_all()
telnet's protocol is pretty straightforward... you just create a TCP connection, and send and receive ASCII data. That's pretty much it.
So all you really need to do is create a program that connects via TCP, then reads characters from the TCP socket and parses it to update the GUI, and/or writes characters to the socket in response to the user manipulating controls in the GUI.
How you would implement that depends a lot on what software you are using to construct your interface. On the TCP side, a simple event loop around select() would be sufficient.
While telnet is almost just a socket tied to a terminal it's not quite. I believe that there can be some control characters that get passed shortly after the connection is made. If your device is sending some unexpected control data then it may be confusing your program.
If you haven't already, go download wireshark (or tshark or tcpdump) and monitor your connection. Wireshark (formerly ethereal) is cross platform and pretty easy to use for simple stuff. Filter with tcp.port == 23
This might be useful reading for you.
I really find Beej's Guide to Network Programming a good introduction to network programming in C.
Download Putty source code. Examine TELNET.C, the Telnet backend for Putty.
Unless the application is trivial, a better starting point would be to figure out how you're going to create the GUI. This is a bigger question and will have more impact on your project than how exactly you telnet into the device. You mention C at first, but then start talking about Python, which makes me believe you are relatively flexible in the matter.
Once you are set on a language/platform, then look for a telnet library -- you should find something reasonable already implemented.
Check out the source code here. It has helped me out a lot in understanding Telnet protocol.
See options in your telnet client: on an arbitrary listening socket and hit escape] to enter the client.
telnet> help
telnet> set ?
Related
I want to know if there is a way to login to ssh with sockets like so:
import socket
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM);
sock.connect(("127.0.0.1",22));
sock.send("username");
sock.send("password");
No, you cannot send username and password directly to the socket.
What goes over the wire is encrypted, and there as well is a certain level of protocol between that.
So you need a layer which provides you with the right protocol on one layer and something which encrypts your communication at a lower level.
Both things can in theory be implemented in Python, but I don't know if such things really exist.
I have a dot-matrix printer LX-300 connected to my computer through the network. How do I send a raw string with ESCP characters directly to my printer in Python?
The computer is connected to the printer through another computer. I need to send a raw string because LX-300 image printing result is blurry.
The Problem
To send data down this route:
Client computer ---> Server (Windows machine) ---> printer (dot-matrix)
...and to not let Windows mess with the data; instead to send the raw data, including printer control codes, straight from the client computer.
My Solution
Here's how I solved a near-identical problem for a small in-house database application:
Step 1) Make the printer network-accessible without Windows getting its fingers in the data routed to it. I accomplished this by installing the printer using the "Generic/Text Only" driver, then installing
RawPrintServer on the Windows machine connected to the printer.
Step 2) Send raw data over the network to the TCP/IP port specified when you set up RawPrintServer (default is 9100). There are various ways to do that, here's what I did:
data = b"\x1B#A String To Print\x1B#" # be sure to use the right codes for your printer
ip_addr = 123.123.123.123 # address of the machine with the printer
port = 9100 # or whatever you set it to
s = socket.socket()
try:
s.connect((ip_addr, port))
s.send(data)
except:
# deal with the error
finally:
s.close()
Background
I thought about the problem in two parts:
Client machine: spitting out the data I need from Python with the correct formatting/control codes for my printer, and sending it across the network
Print server machine: transmitting the data to the locally connected printer
Number 1 is the easy part. There are actually some libraries in PyPI that may help with all the printer codes, but I found most of them are aimed at the little point-of-sale label printers, and were of limited use to me. So I just hard-coded what I needed into my Python program.
Of course, the way you choose to solve number 2 will effect how you send the data from Python. I chose the TCP/IP route to avoid dealing with Samba and Windows print issues.
As you probably discovered, Windows normally tries very hard to convert whatever you want to print to a bitmap and run the printer in graphics mode. We can use the generic driver and dump the data straight into the (local) printer port in order to prevent this.
The missing link, then, is getting from the network to the local printer port on the machine connected to the printer. Again, there are various ways to solve this. You could attempt to access the Windows printer share in some way. If you go the TCP/IP route like I did, you could write your own print server in Python. In my case, the RawPrintServer program "just worked" so I didn't investigate any further. Apparently all it does is grab incoming data from TCP port 9100 and shove it into the local printer port. Obviously you'll have to be sure the firewall isn't blocking the incoming connections on the print server machine. This method does not require the printer to be "shared" as far as Windows is concerned.
Depending on your situation (if you use DHCP), you might need to do some extra work to get the server's IP address in Python. In my case, I got the IP for free because of the peculiarity of my application.
This solution seems to be working out very well for me. I've got an old Panasonic printer running in Epson ESC/P compatibility mode connected to a Windows 7 machine, which I can print to from any other computer on the local network. Incidentally, this general idea should work regardless of what OS the client computer is running.
Ultimately, you will need and want to write your own wrapper/script to do this. And since you are using a distribution of Linux, this is relatively easy.
On a Linux OS, the simplest way to issue a print job is to open a subprocess to the lpr. Generally, using lpr lets you access the printer without the need to be logged in as root (being a superuser), which is desirable considering the amount of damage that can be done while logged in as a "superuser".
Code like the following:
import subprocess
lpr = subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE)
lpr.stdin.write(data_to_send_to_printer)
Should be a good jumping off point for you. Essentially, this code should allow you to accomplish what you need.
Be careful though; depending on your privilege levels, a call to open a subprocess might need root level/Superuser permissions.
Subprocesses generally inherit the User IDs and access rights by the user that is running the command. For example, if the subprocess is created by a root user, then you will need root user/Superuser rights to access that subprocess.
For more information, check out the hyperlinks I've included in the post.
Good luck!
Is it possible to telnet to a server and from there telnet to another server in python?
Since there is a controller which I telnet into using a username and password, and from the controller command line I need to login as root to run linux command. How would I do that using python?
I use the telentlib to login into router controller but from the router controller I need to log in again to get into shell. Is this possible using python?
Thanks!
Just checked it with the hardware I have in hand & telnetlib. Saw no problem.
When you are connected to the first device just send all the necessary commands using telnet.write('cmd'). It may be sudo su\n, telnet 192.168.0.2\n or whatever else. Telnetlib keeps in mind only its own telnet connection, all secondary connections are handled by the corresponding controllers.
Have you looked into using expect (there should be a python binding); basically, what I think you want to do is:
From your python script, use telnetlib to connect to server A (pass in username/password).
Within this "socket", send the remaining commands, e.g. "telnet serverB" and use expect (or some other mechanism) to check that you get back the expected "User:" prompt; if so, send user and then password and then whatever commands, and otherwise handle errors.
This should be very much doable and is fairly common with older stuff that doesn't support a cleaner API.
You can use write() to issue the sudo command.
tn.write("sudo\n")
You could also use read_until() to help with the credentials.
tn.read_until("login: ")
tn.write(user + "\n")
if password:
tn.read_until("Password: ")
tn.write(password + "\n")
I want to write a Python Twisted server that serves text to its clients, and I want the clients to be able to write text back to manipulate the server. I will use Telnet, and the clients will use Putty or some similar terminal...I would also be open to using SSH if it is easier to do this.
My question is, how do I configure the server so that the client can send raw, unbuffered bytes (I don't want the user to have to press enter after a command)? Also, is there a way to change the configuration mid-session so that I can change back and forth to and from buffered/unbuffered bytes?
I think it is Telnet option 34 "Linemode" --- http://www.freesoft.org/CIE/RFC/1700/10.htm
I just don't know how to set up Twisted to use that...
Any help setting this up for Telnet or SSH is appreciated!!!
Thanks!
twisted.conch.telnet.TelnetBootstrapProtocol is a good example of how to do some option negotiation. It also happens to perform some LINEMODE negotiation. Take a look at the implementation for details, but here's a snippet that shows the server asking the client to enable linemode, naws, and sga:
for opt in (LINEMODE, NAWS, SGA):
self.transport.do(opt).addErrback(log.err)
A real server might want to do more error handling than log.err if the negotiation fails, since the client will be left in a state that is presumably not ideal for use with the server.
Also take a look at some of the funky terminal demos that come with Twisted. These do lots of character-at-a-time processing.
I've developed an application that is essentially just a little ftp server with the ability to specify which directory you wish to share on startup. I'm using ftplib for the server because it's sick easy. The only issue I'm having is that if you are behind a router you have to manually forward the ports on your router and I'm finding that it's a little too complicated for my users (aka co-workers/clients).
So I've been looking for a simple solution to open ports but I'm finding that most APIs are too broad and way over my head. Does someone know of a solution that would be relatively simple to implement?
Note: It will really only be used on windows although cross-platform compatibility would be welcomed. If there is a windows only solution that is simpler then I would opt for that.
Thanks!
Simple example for miniupnp. It creates a mapping on the discovered gateway from external port 43210 to the interface connected to port 43210 on the interface connected to the discovered gateway.
import miniupnpc
upnp = miniupnpc.UPnP()
upnp.discoverdelay = 10
upnp.discover()
upnp.selectigd()
port = 43210
# addportmapping(external-port, protocol, internal-host, internal-port, description, remote-host)
upnp.addportmapping(port, 'TCP', upnp.lanaddr, port, 'testing', '')
The protocol you want is called IGD (for Internet Gateway Device) and is based on UPNP. It allows a client program (yours) to discover the router on the network (using UPNP) and then ask it to forward a specific port.
This is supported by most home routers, and the technique is used by a lot of services like BitTorrent or multiPlayer games, bit it's a bit complicated to use or implement. There are several open source libraries that support IGD and one of the simplest one (which is also cross-platform) is "miniupnp": see http://miniupnp.free.fr/
Looks like there are a few options, one being miniupnp. There are also python bindings for GNUPnP here. For windows minupnp will work, or you could go pure python with miranda-upnp.
There is a nice example of the python GNUPnP bindings being used to open ports on a router here.
In that example the lease time is set to 0, which is unlimited. See here for the definition of add_port.
A simple example might be:
#! /usr/bin/python
import gupnp.igd
import glib
from sys import stderr
my_ip = YOUR_IP
igd = gupnp.igd.Simple()
igd.external_ip = None
main = glib.MainLoop()
def mep(igd, proto, eip, erip, port, localip, lport, msg):
if port == 80:
igd.external_ip = eip
main.quit()
def emp(igd, err, proto, ep, lip, lp, msg):
print >> stderr, "ERR"
print >> stderr, err, proto, ep, lip, lp, msg
main.quit()
igd.connect("mapped-external-port", mep)
igd.connect("error-mapping-port", emp)
#igd.add_port("PROTO", EXTERNAL_PORT, INTERNAL_IP, INTERNAL_PORT, LEASE_DURATION_IN_SECONDS, "NAME")
igd.add_port("TCP", 80, my_ip, 8080, 86400, "web")
main.run()
There is an article explaining how to use the Windows IGD COM object with win32com.
I looked for this for many days. I was unable to install miniupnpc using pip for python 3.
I solved this isue with an implementation found here which will work for python 2.
I forked it and make the changes to be used on python 3, you can find it Here
This implementation is by far the simplest I have seen and works well.