#!/usr/bin/env python # LICENSE=""" Copyright (c) 2014 John Lane MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. http://www.opensource.org/licenses/mit-license.php """ DESCRIPTION=""" telscript : Execute a script over telnet Establishes a telnet session to a remote host and executes a series of commands there. You can write commands in a script and then execute it $ telscript < script Or, most probably: $ telscript -n myhost -u myusername -p mypassword < script You can add a "shebang" to the script file of the form: #!/usr/bin/telscript -n myhost -u myusername -p mypassword and make it executable `chmod +x myscript` then you can execute it directly: $ ./myscript If username and/or password are omitted then an attempt will be made to obtain them from "~/.netrc". For command help: $ telscript --help (c) John Lane 2013-02-02. This version 2014-09-27. Licensed under the MIT License. https://github.com/johnlane/telscript """ # References: # import sys import atexit import telnetlib import socket import argparse import re import os import netrc def abort(error_message): sys.exit("%s. Cannot continue." % error_message) ############################################################################################## # A very primitive message logger LOG_DEBUG = 'debug' LOG_VERBOSE = 'verbose' def verbose(message): log(LOG_VERBOSE,message) def debug(message): log(LOG_DEBUG,message) def log(level,message): if args.loglevels != None and level in args.loglevels: print("(%s) %s" % (level,message)) def debug_enabled(): return args.loglevels != None and LOG_DEBUG in args.loglevels def verbose_enabled(): return args.loglevels != None and LOG_VERBOSE in args.loglevels ############################################################################################## class Telnet(telnetlib.Telnet,object): pass def readit(self,expected): received = self.read_until(expected,5) if re.search(expected, received, re.IGNORECASE): verbose(received) else: abort("Unexpected reply from server:Expected '%s', got '%s'" % (expected,received)) if sys.version > '3': def read_until(self,expected,timeout=None): expected = bytes(expected, encoding='utf-8') received = super(Telnet,self).read_until(expected,timeout) return str(received, encoding='utf-8') def write(self,buffer): buffer = bytes(buffer, encoding='utf-8') super(Telnet,self).write(buffer) def expect(self,list,timeout=None): for index,item in enumerate(list): list[index] = bytes(item, encoding='utf-8') match_index, match_object, match_text = super(Telnet,self).expect(list,timeout) return match_index, match_object, str(match_text, encoding='utf-8') def main(name, argv): def cleanup(): try: if tn: tn.close if input and input is not sys.stdin: input.close() except NameError: pass # move along, nothing to do atexit.register(cleanup) # When invoked via a shebang, args are packaged differently to when invoked directly # http://stackoverflow.com/q/14674960/712506 if len(argv) >= 2 and name[0] == '/' and os.path.isfile(argv[1]) and os.access(argv[1], os.X_OK): input = open(argv[1]) arglist = argv[0].split() + argv[2:] else: arglist = argv input = sys.stdin # Arguments global args parser = argparse.ArgumentParser(description=DESCRIPTION, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('--license', action='store_true', default=False, dest='license', help='show the MIT License') parser.add_argument('-n', '--hostname', action='store', dest='hostname', help='Remote host to connect to') parser.add_argument('-u', '--username', action='store', dest='username', help='Username ') parser.add_argument('-p', '--password', action='store', dest='password', help='Password') parser.add_argument('-i', '--ignore-regex', action='store', dest='ignore_regex', help='Regular Expression defining lines in script to be ignored (e.g. comments)') parser.add_argument('-v', '--verbose', action='append_const', const=LOG_VERBOSE, dest='loglevels', help='Enable verbose message output') args = parser.parse_args(arglist) if args.license == True: print(LICENSE) return 0 username = args.username password = args.password hostname = 'localhost' if args.hostname == None else args.hostname ignore_regex = '^ *[#/!]' if args.ignore_regex == None else args.ignore_regex if not (username and password): try: host_netrc = netrc.netrc() except (IOError,netrc.NetrcParseError) as e: abort("Failed to read credentials for %s: %s" % (hostname,str(e))) auth=host_netrc.authenticators(hostname) if auth: if not username: username = auth[0] if not password: password = auth[2] else: abort("Insufficient credentials") verbose("Hostname: %s" % hostname) verbose("Username: %s" % username) verbose("Password: %s" % password) try: tn = Telnet(hostname) except socket.error as e: abort("Could not connect to %s (%s)" % (hostname, e[1])) # Send Username and Password tn.readit('Username : ') tn.write(username+ "\r") tn.readit("Password : ") tn.write(password+ "\r") # Check responses and abort unless prompt receuived match_index, match_object, match_text = tn.expect(['=>','Invalid username/password'],10) if match_index > 0: abort(filter(lambda c: c not in '*\n', match_text)) if input.isatty(): # Interactive mode http://stackoverflow.com/questions/26098600 print("Started interactive session on %s\n%s" % (hostname,match_text)), while True: tn.write(input.readline() + '\r') try: print(tn.read_until('{admin}=>')), except EOFError: break else: # Scripted mode # Send each input line in turn, display its output for line in input: line = line.rstrip('\n') if line and re.match(ignore_regex,line) is None: try: tn.write(line + "\r") print(tn.read_until('=>')) except Exception as e: abort(e[1]) sys.exit(main(sys.argv[0], sys.argv[1:]))