Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- """
- This program connects to the provieded ssh connections
- and executes the commnd to all successful open connections
- and print the output to the stdout.
- After all commands has been executed, it cloeses all connections.
- """
- import logging
- from pexpect import pxssh
- # here you should work with argparse
- # docopts is cool, but then you've an aditional
- # depencency
- # stipped out the cool colourful terminal stuff
- # it's just to explain a little bit the magic
- # and oo style
- class ClientError(Exception):
- # just a class for an exception to be
- # more concrete
- pass
- class Client:
- """
- This class is a wrapper around pxssh.
- """
- def __init__(self, host, port, user, password):
- """
- host: ip address or domain name of the host you want to connect to
- port: int, port number of ssh
- user: username to login
- password: password to login
- """
- self.host = host
- self.port = port
- self.user = user
- self.password = password
- options = {"StrictHostKeyChecking": "no", "UserKnownHostsFile": "/dev/null"}
- # StrictHostKeyChecking saves you from errors, when host is unknown
- # the second argument is to prevent saving the host in der knownhostsfile
- # echo = False prevents repeating the command when accessing session.before
- self.session = pxssh.pxssh(echo=False, options=options)
- def connect(self):
- """
- Connects to the client
- """
- try:
- self.session.login(self.host, self.user, self.password, port=self.port)
- except Exception as e:
- # this will raise the clieht error and
- # will forward the error message to
- # the more concrete class
- # client error
- raise ClientError(e)
- def send_command(self, cmd):
- """
- Send a command to the client and returns the output without repeating the command.
- """
- self.session.sendline(cmd)
- self.session.prompt()
- # session.before are bytes. encoding depends on the target system
- # I think. Calling decode without arguments is interpreted as utf-8
- # this raise an error if the encoding is a different.
- # The __init__ method of the class pxssh takes also a keyword argument for encoding
- # look into the documentation
- return self.session.before.decode()
- class Botnet:
- """
- This class handles many ssh connections.
- """
- def __init__(self, clients):
- """
- clients: (host: str, port: int, user: str, password: str)
- """
- self.clients = []
- for host, port, username, password in clients:
- client = Client(host, port, username, password)
- try:
- client.connect()
- except ClientError as e:
- #log.error(e) there is the host missing
- log.error('Could not establish connection to host {}:{}'.format(client.host, client.port))
- else:
- log.info('Connected to: {}:{}'.format(client.host, client.port))
- self.clients.append(client)
- def __enter__(self):
- """
- Returns a Botnet object, where all connections are
- closed when leaving the context manager
- """
- # just making a context manager
- return self
- def __exit__(self, *args):
- # is called, when the with block has been left
- # is also called when sys.exit() is called somewhere
- # also called when an exeption has been raised inside the with block
- # or the called method of the class itself, when it's not catched
- for client in self.clients:
- log.info('Closing client session of host: {}:{}'.format(client.host, client.port))
- client.session.logout()
- def command(self, command):
- """
- Sends a command to all connections.
- Prints the returned text to stdout.
- """
- # changed the method name to command
- # botnet.command sounds better as botnet.botnet_command
- for client in self.clients:
- output = client.send_command(command)
- print('Client: {}:{}\nCommand: {}\n{}\n'.format(client.host, client.port, command, output))
- # data should go to stdout, here is print ok, but you
- # can also yield the content
- # In the case of using a yield statement inside a
- # function, makes a generator
- # then you've to iterate over the generator
- def main():
- """
- Description of main function
- But not needed......
- """
- # just as an example
- # later you should learn how to put this information
- # into a txt file for example
- # it can be for example a csv file
- # don't use pickle for it
- clients = [('localhost', 22, 'username', 'passwort'), ('localhost', 22, 'username', 'passwort')]
- with Botnet(clients) as botnet:
- # makes a instance botnet of class Botnet
- # block of the
- # context manager
- # very powerful
- botnet.command('whoami')
- botnet.command('ip addr show')
- # leaving the block call the __exit__ method
- # in this case, it will logout all clients
- if __name__ == '__main__':
- # good shell citizens are using logging.
- # Logs are going to stderr
- logging.basicConfig()
- log = logging.getLogger(__file__)
- # normally __name__, but this will give you __main__ back
- log.setLevel(logging.INFO) # here you can set the logging setLevel
- #log.setLevel(logging.ERROR)
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement