Статья Изучаем Python на практике. Пишем чекер SSH серверов.

Приветствую всех, кто изучает Python и хочет перейти от сухой теории к практическому применению полученных знаний.
Просмотрев форум codeby.net нашел несколько материалов, где авторы делились своим опытом и пробовали свои силы в написании небольших скриптов. К сожалению большинство авторов использовали процедурный тип написания кода. В то время как создание, поддержание и развитие приложения даже средней сложности требует ООП подхода.
Попробуем в небольшом проекте применить ООП, в самом простом виде.
Автор будет очень благодарен более опытным товарищам, если они наставят на путь истинный и, возможно, дадут пару подзатыльников для дальнейшего развития в нужном направлении.
Не смотря на свой возраст - автор начинающий программист-любитель, самоучка, а без посторонней помощи в программировании можно барахтаться годами примерно на одном уровне. Именно поэтому и пишу.

Для тех, кто сразу хочет развернуть проект, скачиваем архив и в папке с архивом выполняем:
Python:
pip install -r requirements.txt

Полный текст программы можно посмотреть в конце поста под спойлером "Весь код".

Итак, приступим. Имеем на входе - текстовый файл, назовем его 'ssh_nocheck.txt' со строками вида:
Python:
username password ipaddress port
Соответственно: логин, пароль, адрес SSH сервера, порт для подключения.

Нужно проверить каждый хост (строку файла) на возможность подключения.
Учетные данные и адрес сервера, принявшего соединение, записать в файл, назовем его goods.txt.

Для тестирования работы скрипта понадобятся SSH аккаунты. Есть сервисы на которых их можно получить легально и бесплатно.
Здесь каталог ссылок на такие сервисы. , к сожалению много мертвых.
Автор воспользовался этим:

Раз уж мы решили применить ООП, посмотрим какие сущности у нас есть в поставленной задаче:
1. файл со списком серверов, нуждающихся в проверке;
2. файл для записи списка серверов, ответивших на запрос при проверке;
3. сам сервер, который нужно проверить, в виде строки во входящем файле.
После написания кода заметил, что дублируются операции по работе с файлами и решил вывести все, что касается файловых операций в отдельный класс.
Таким образом получилось 4 класса:

  1. class InputOutput - будет отвечать за чтение/запись в файл
  2. class InputList - будет получать данные из файла-списка и хранить некоторые параметры при работе программы
  3. class Host - будет хранить данные каждого хоста и методы по обработке
  4. class OutputList - будет сохранять в новый файл список серверов, прошедших проверку

Продвигаться в написании классов будем по порядку решения поставленной задачи.
Начнем с точки входа в программу. По умолчанию это метод main.

Python:
def main():
    parser = cmd_arg_parser()
    namespace = parser.parse_args(sys.argv[1:])
    input_f = namespace.input_file
    output_f = namespace.output_file
    output_list = OutputList()
    input_list = InputList()
    host = Host()
    io = InputOutput(input_f, output_f, input_list, output_list)
    input_list.handling_list(output_list, host, io)
    print('Filtered:', input_list.bad_host_count, 'bad hosts.', 'Passed the test:', output_list.count_of_good_hosts, 'hosts')

Пропустим пока строки 2-5. В строках 6-9 создаются объекты на основе классов.
Обратите внимание на строки 8 и 9. Здесь не просто создаются объекты, но им передаются другие объекты.
Так в строке 8 создается объект Host() и присваевается переменной host. В скобках передаются два объекта, которые были созданы в строками выше - это объекты входящего и исходящего списков. Они передаются в объект Host(), что бы он мог взаимодействовать со списками: менять значения их полей и использовать их методы.
В строке 10 вызывается метод объекта input_list. Обращение к методу объекта происходит через переменную, которой присвоен этот объект, после которой ставится точка.
После точки можно обратится к полю объекта или вызвать метод. Если вызывается метод, то он заканчивается круглыми скобками. Внутри скобок передаются параметры, необходимые для нормальной работы метода. В данном случае передаются 3 объекта.

Переходим к созданию классов.
Поскольку сначала нужно получить данные для проверки создадим класс class InputList.
Проанализируем какие атрибуты (поля класса) будут у объекта.
Python:
class InputList:
    def __init__(self):
        self.host_count = 0
        self.bad_host_count = 0
        self.current_line_count = 0
def __init__(self): это метод конструктор, он выполняется при создании объекта InputList.
self.host_count = 0 количество проверяемых ssh серверов
self.bad_host_count = 0 количество серверов, не ответивших на запрос
self.current_line_count = 0 номер текущей строки файла, из которого читается список
Все поля пустые, потому, что вновь созданный объект не загрузил пока никакие данные.

Создаем класс OutputList.
Python:
class OutputList:
    def __init__(self):
        self.count_of_good_hosts = 0
Конструктор очень простой, все, что мы будем хранить в объекте это количество проверенных хостов, они будут записаны в файл.

Создаем класс Host.
Python:
class Host:
    def __init__(self):
        self.user = None
        self.password = None
        self.ip = None
        self.port = None
        self.location = None
        self.start_time = timer()
        self.host_access_time = 0
В полях этого класса будут хранится учетные данные и адрес сервера, а так же его геолокация, и время доступа при авторизации на сервере.

Последний класс, который мы создадим это класс, отвечающий за файловые операции - InputOutput.
Python:
class InputOutput:
    def __init__(self, input_f, output_f, input_list, output_list):
        self.output_file = output_f
        self.input_file = input_f
        self.output_list = output_list
        self.input_list = input_list
В конструктор передаются имена входящего файла и файла с результатом, а так же объекты списков.

Теперь приступим к созданию методов классов. А вот тут начинаются сложности с объяснением. Для более ясного понимания лучше смотреть весь файл с программой, куски с комментариями будут просто подсказками.

Продолжаем наполнять класс InputList. Для начала узнаем сколько хостов нужно будет проверить, подсчитав количество строк в файле.
Python:
def hosts_counter(self, io):
    print('Counting host in file:', io.input_file)
    for line in io.read_data_from_file(flag='r'):
        self.host_count += 1
    return self.host_count
Для этого нужно прочитать файл. При чтении файла обычно создается список его содержимого (список списков строк), который помещается в оперативную память. Здесь есть определенная проблема - если файл будет достаточно большой, а ресурсы сервера ограничены, то чтение большого файла может израсходовать всю оперативную память виртуальной машины и привести системы в уход в swap. Чтобы такого не случилось лучше читать, обрабатывать и записывать по одной отдельной строке из файла.
Первый аргумент метода hosts_counter - self. self ссылается на сам класс, указывая, что это не какая то внешняя функция а именно метод этого класса. Поскольку все файловые операции будет выполнять класс InputOutput, вторым аргументом передается ссылка на объект io (см. метод main).
Во второй строке мы выводим на печать текст с переменной io.input_file - это обращение к полю объекта io с названием input_file.
Дальше создаем цикл, который последовательно прочтет все строки файла. На этот раз вызывается метод объекта io - read_data_from_file(flag='r') с именованным аргументом, который будет использоваться далее при открытии файла в режиме "только чтение". Если строка файла прочитана и не вызвано исключение в методе io.read_data_from_file(), то счетчик хостов увеличивается на единицу self.host_count += 1. В последней строке функция возвращает с помощью оператора return результат своей работы - поле объекта input_list подсчитанную сумму строк: self.host_count.
В методе hosts_counter() была ссылка на метод объекта io io.read_data_from_file() - создадим его в классе InputOutput.
Python:
def read_data_from_file(self, flag):
    try:
        with open(self.input_file, flag) as file:
            for line in file:
                yield line.strip().split(' ')
    except IOError:
        print("can't read from file, IO error")
        exit(1)
Вот здесь и появился именованный аргумент флаг. Действие функции обернуты в try-except для предотвращения падения программы без выясненной причины. В нашем случае если файл по какой то причине не может быть прочитан, то продолжать выполнение программы бессмысленно, поэтому она завершится после сообщения об ошибке ввода-вывода. И вот мы пришли к тому, что было сказано ранее о необходимости чтения файла и дальнейшей его обработки построчно. Это достигается использованием оператора yield. Если кратко, yield останавливает выполнения цикла до следующего вызова итератора цикла. То есть если просто вызвать где то в коде метод read_data_from_file() он прочтет только 1-ую строку файла и приостановит свою работу. Для того, что бы он отработал по всем строкам файла, метод должен быть вызван внутри другого цикла, в нашем случае он является итерируемым объектом (for line in io.read_data_from_file) в методе hosts_counter. Команда line.strip().split(' ') убирает символ перехода на новую строку и разбивает строку на подстроки по разделителю пробел. Таким образом данные о хосте выглядят как строка строк [[login], [pass], [ip], [port]].

Мы вынужденно отвлеклись от создания методов класса InputList, снова возвращаемся к нему.
Переходим к созданию метода, фактически управляющего всей последующей программой. Метод находится в InputList по той причине, что далее идет обработка данных именно этого списка. Но такое решение вопрос спорный и возможно такой метод было бы лучше разместить в функции main?
Напишите ваше мнение о размещении этого метода в комментариях.
Python:
def handling_list(self, output_list, host, io):
    print('Found', self.hosts_counter(io), 'hosts in list of file', io.input_file)
    for line in io.read_data_from_file(flag='r'):
        self.current_line_count += 1
        print('handling line#', self.current_line_count)
        check_result = host.check_host_data(line)
        if check_result:
            host.extract_host_data_from_line(line)
            connection = host.connect_to_host()
            if connection:
                prepare_data = output_list.prepare_data_to_write(line, host)
                write_line = io.write_data_to_file(prepare_data, output_list, flag='a')
                if write_line:
                    print('recorded line#', output_list.count_of_good_hosts, 'of', self.host_count)
            else:
                self.bad_host_count += 1
        else:
            self.bad_host_count += 1
Переходим к классу Host. Метод проверки данных для подключения check_host_data().
Python:
def check_host_data(self, line):
    print('Checking data of host', line[2])
    if len(line) == 4:
        return True
    else:
        print('no valid data in line')
        return False
Цикл, во второй строке дублирует цикл из предыдущего метода, проходя по итерируемому объекту читает строки из файла, увеличивая счетчик текущей строки на единицу, а затем переходит к строке проверки данных строки check_result = host.check_host_data(line). Дело в том, что данные в строке могут быть не корректны, например, может не хватать порта или пароля. Если список len(line) == 4 содержит 4 объекта, то проверка пройдена. Можно переходить к попытке подключения check_host(). Мы все еще в классе Host.
Python:
def check_host(self, line):
    if self.extract_host_data_from_line(line):
        print("Trying to connect to %s" % self.ip)
        self.connect_to_host()
        return True
    else:
        return False
Если удается извлечь все данные для подключения if self.extract_host_data_from_line(line), то можно подключаться.
Обратите внимание, переменные с self.user присваивают значением полям объекта Host. Специфика данного случая в том, что все созданные объекты находятся в единичном экземпляре. Даже вроде бы такой объект как host, нужен лишь при проверке своих данных, а дальше его поля перезаписываются данными из следующей строки.
Python:
def extract_host_data_from_line(self, data):
    self.user = data[0]
    self.password = data[1]
    self.ip = data[2]
    self.port = data[3]
    return True
После заполнения всех необходимых переменных для подключения делаем попытку соединения сервером self.connect_to_host() (мы все еще в классе Host)
Python:
def connect_to_host(self):
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname=self.ip, username=self.user, password=self.password, port=self.port, timeout=3)
        print('Connected to host', self.ip, 'Access time to host:', self.access_time(), 'seconds')
        return True
    except paramiko.AuthenticationException:
        print("Authentication failed when connecting to", self.ip)
        print('Host marked as bad.')
        return False
    except ConnectionError:
        print("Could not connect to %s" % self.ip)
        return False
Для работы используется библиотека paramiko, ее предварительно нужно установить
Python:
pip install paramiko
и импортировать в файле
Python:
import paramiko
Дальше дело самой библиотеки - создать подключение с учетными данными которые мы ей предоставим. Если подключение установлено, считаем проверку законченной. Если соединится не получилось, то тут два варианта либо сервер недоступен except ConnectionError:, либо неправильные учетные данные except paramiko.AuthenticationException:.
self.access_time() - считает время потраченное на подключение, что то вроде пинга, для которого я не нашел простого решения для Python, - все библиотеки, рассмотренные мной, вызывали нативную для ОС системную команду ping, вывод которой нужно было парсить.
Python:
def access_time(self):
    self.host_access_time = timer() - self.start_time
    return round(self.host_access_time, 2)
Возвращаемся к методу handling_list() класса InputList.
Python:
if connection:
    prepare_data = output_list.prepare_data_to_write(line, host)
Если соединение с сервером завершилось удачно, подготавливаем данные для записи в файл goods.txt. Работа с данными для результирующего файла возложена на метод prepare_data_to_write() класса OutputList. Превращаем все данные в строки иначе их не удастся объединить в одну строку, не забывая добавить в конце символ перехода на новую строку '\n', и возвращаем новую строку с данными для записи.
Python:
def prepare_data_to_write(self, line, host):
    joined = ' '.join(line) + ' '
    location = str(host.get_location(host.ip)) + ' '
    accsesstime = str(host.host_access_time)
    new_line = joined + location + accsesstime + '\n'
    return new_line
В файл goods.txt будут выводится не только учетные данные из исходного файла, но и время доступа к серверу во время попытки подключения и геолокация сервера.
Для определения местоположения сервера используется библиотека geoip2, ее предварительно нужно установить
Python:
pip install geoip2
и импортировать в файле
Python:
import geoip2.database
Для работы библиотеки скачиваем файл базы отсюда . И в класс Host добавляем метод
get_location(), который получает параметр в виде адреса, библиотека ищет совпадение по БД и возвращает результат в виде название страны на английском.
Python:
def get_location(self, ip):
    reader = geoip2.database.Reader('GeoLite2-Country.mmdb')
    response = reader.country(ip)
    return response.country.names['en']
Снова возвращаемся к методу handling_list() класса InputList.
Python:
write_line = io.write_data_to_file(prepare_data, output_list, flag='a')
    if write_line:
        print('recorded line#', output_list.count_of_good_hosts, 'of', self.host_count)
Пишем подготовленную строку в файл с помощью метода write_data_to_file() класса InputOutput. Управляющая конструкция с циклом for line in io.read_data_from_file(flag='r') находится в методе handling_list() класса InputList.
Python:
def write_data_to_file(self, line, output_list, flag):
    try:
        with open(self.output_file, flag) as file:
            file.write(line)
            output_list.count_of_good_hosts += 1
        return True
    except IOError:
        print("Can't write to output file, IO error")
        exit(1)
Аналогично, как и при чтении файла, заворачиваем всю конструкцию в try-except, с одной особенностью - параметр передаваемый при открытии файла будет не 'r', как при чтении, а 'a' add, строки будут добавлятся. В случае удачной записи поле с переменной проверенных хостов увеличивается на единицу. Если по каким то причинам запись невозможно работа программы будет остановлена.
Осталось обсудить первые несколько строк в функции main().
Для того, что бы можно было вводить собственные имена файлов для ввода ввода-вывода нужно обрабатывать аргументы переданные программе во время запуска. Для этого будет использоваться библиотеку argparse.
Python:
pip install argparse
в файле
Python:
import argparse
Работу парсера вынесем в отдельную функцию cmd_arg_parser().

Создаем объект парсера:
Python:
parser = argparse.ArgumentParser()
и передаем ему два аргумента для входящего и исходящего файла
Python:
parser.add_argument('-i', '--input_file', default='ssh_nocheck.txt')
parser.add_argument('-o', '--output_file', default='goods.txt')
именованные аргументы default используются для имен файлов по умолчанию, если при старте программы пользователь не ввел собственные имена файлов.
Python:
def cmd_arg_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--input_file', default='ssh_nocheck.txt')
    parser.add_argument('-o', '--output_file', default='goods.txt')
    return parser


def main():
    parser = cmd_arg_parser()
    namespace = parser.parse_args(sys.argv[1:])
    input_f = namespace.input_file
    output_f = namespace.output_file
Вот и все, 164 строки кода.

Python:
#!/usr/bin/python

import paramiko
from timeit import default_timer as timer
import sys
import argparse
import geoip2.database


class InputOutput:
    def __init__(self, input_f, output_f, input_list, output_list):
        self.output_file = output_f
        self.input_file = input_f
        self.output_list = output_list
        self.input_list = input_list

    def read_data_from_file(self, flag):
        try:
            with open(self.input_file, flag) as file:
                for line in file:
                    yield line.strip().split(' ')
        except IOError:
            print("can't read from file, IO error")
            exit(1)

    def write_data_to_file(self, line, output_list, flag):
        try:
            with open(self.output_file, flag) as file:
                file.write(line)
                output_list.count_of_good_hosts += 1
            return True
        except IOError:
            print("Can't write to output file, IO error")
            exit(1)


class Host:
    def __init__(self):
        self.user = None
        self.password = None
        self.ip = None
        self.port = None
        self.location = None
        self.start_time = timer()
        self.host_access_time = 0

    def access_time(self):
        self.host_access_time = timer() - self.start_time
        return round(self.host_access_time, 2)

    def get_location(self, ip):
        reader = geoip2.database.Reader('GeoLite2-Country.mmdb')
        response = reader.country(ip)
        return response.country.names['en']

    def check_host_data(self, line):
        print('Checking data of host', line[2])
        if len(line) == 4:
            return True
        else:
            print('no valid data in line')
            return False

    def extract_host_data_from_line(self, data):
        self.user = data[0]
        self.password = data[1]
        self.ip = data[2]
        self.port = data[3]
        return True

    def connect_to_host(self):
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(hostname=self.ip, username=self.user, password=self.password, port=self.port, timeout=3)
            print('Connected to host', self.ip, 'Access time to host:', self.access_time(), 'seconds')
            return True
        except paramiko.AuthenticationException:
            print("Authentication failed when connecting to", self.ip)
            print('Host marked as bad.')
            return False
        except ConnectionError:
            print("Could not connect to %s" % self.ip)
            return False

    def check_host(self, line):
        if self.extract_host_data_from_line(line):
            print("Trying to connect to %s" % self.ip)
            self.connect_to_host()
            return True
        else:
            return False


class OutputList:
    def __init__(self):
        self.count_of_good_hosts = 0

    def write_data(self, io, data):
        io.write_data_to_file(data, flag='a')

    def prepare_data_to_write(self, line, host):
        joined = ' '.join(line) + ' '
        location = str(host.get_location(host.ip)) + ' '
        accsesstime = str(host.host_access_time)
        new_line = joined + location + accsesstime + '\n'
        return new_line


class InputList:
    def __init__(self):
        self.host_count = 0
        self.bad_host_count = 0
        self.current_line_count = 0

    def hosts_counter(self, io):
        print('Counting host in file:', io.input_file)
        for line in io.read_data_from_file(flag='r'):
            self.host_count += 1
        return self.host_count

    def handling_list(self, output_list, host, io):
        print('Found', self.hosts_counter(io), 'hosts in list of file', io.input_file)
        for line in io.read_data_from_file(flag='r'):
            self.current_line_count += 1
            print('handling line#', self.current_line_count)
            check_result = host.check_host_data(line)
            if check_result:
                host.extract_host_data_from_line(line)
                connection = host.connect_to_host()
                if connection:
                    prepare_data = output_list.prepare_data_to_write(line, host)
                    write_line = io.write_data_to_file(prepare_data, output_list, flag='a')
                    if write_line:
                        print('recorded line#', output_list.count_of_good_hosts, 'of', self.host_count)
                else:
                    self.bad_host_count += 1
            else:
                self.bad_host_count += 1


def cmd_arg_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--input_file', default='ssh_nocheck.txt')
    parser.add_argument('-o', '--output_file', default='goods.txt')
    return parser


def main():
    parser = cmd_arg_parser()
    namespace = parser.parse_args(sys.argv[1:])
    input_f = namespace.input_file
    output_f = namespace.output_file
    output_list = OutputList()
    input_list = InputList()
    host = Host()
    io = InputOutput(input_f, output_f, input_list, output_list)
    input_list.handling_list(output_list, host, io)
    print('Filtered:', input_list.bad_host_count, 'bad hosts.', 'Passed the test:', output_list.count_of_good_hosts, 'hosts')



if __name__ == "__main__":
    main()
 

Вложения

  • ssh_parser.zip
    3,4 МБ · Просмотры: 1 219
  • kisspng-functional-programming-in-python-computer-programm596729048.jpg
    kisspng-functional-programming-in-python-computer-programm596729048.jpg
    40 КБ · Просмотры: 879

dark2strike

Green Team
16.04.2017
43
42
BIT
0
Так в строке 8 создается объект Host() и присваевается переменной host. В скобках передаются два объекта, которые были созданы в строками выше - это объекты входящего и исходящего списков.

При этом в коде написано host = Host() непонятно, где там в скобках передаются два объекта...

Ну и вообще, не дочитал пока статью, но меня постоянно мучает мысль, что для данной задачи OOP это как из пушки по воробьям. Единственное для чего могло бы это пригодиться, что бы сделать красивый асинк. Но почему-то мне кажется, что в этой разработке никакого асинка не встретится.
 
  • Нравится
Реакции: SoloSubtle и darklight

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
Ну и вообще, не дочитал пока статью, но меня постоянно мучает мысль, что для данной задачи OOP это как из пушки по воробьям.

У вас тоже есть своя правда. host = Host() это затенение имён, неудачно сделано. Если не придираться, то я думаю ТС просто хотел показать использование классов в программе.
 
  • Нравится
Реакции: SoloSubtle и darklight

darklight

Green Team
18.10.2018
45
72
BIT
2
У вас тоже есть своя правда. host = Host() это затенение имён, неудачно сделано. Если не придираться, то я думаю ТС просто хотел показать использование классов в программе.
В посте много неудачно сделано. Хотел отредактировать, но, как я понимаю, через какое то время возможность редактирования пропадает.
За прошедшие 2 дня 2 раза переписал скрипт :)
Добавил опции включения-отключения гео и времени доступа через флаги при запуске, убрал класс InputOutput, логику работы вынес в функцию main().
Структура стала намного лучше и понятней.
Вот последний вариант:
Python:
#!/usr/bin/python

import paramiko
from timeit import default_timer as timer
import sys
import argparse
import geoip2.database


class Host:
    def __init__(self):
        self.user = None
        self.password = None
        self.ip = None
        self.port = None
        self.location = None
        self.start_time = timer()
        self.host_access_time = 0

    def access_time(self):
        self.host_access_time = timer() - self.start_time
        return round(self.host_access_time, 2)

    def get_location(self, ip):
        reader = geoip2.database.Reader('GeoLite2-Country.mmdb')
        response = reader.country(ip)
        return response.country.names['en']

    def hosts_counter(self, input_list):
        print('Counting host in file:', input_list.file)
        for line in input_list.read_file(input_list.file):
            input_list.hosts_count += 1
        return input_list.hosts_count

    def check_host_data(self, line):
        print('Checking data of host', line[2])
        list_len = len(line)
        if list_len == 4 or list_len == 3:
            return list_len
        else:
            print('no valid data in line')
            return False

    def extract_host_data_from_line(self, line, check_result):
        if check_result == 4:
            self.user = line[0]
            self.password = line[1]
            self.ip = line[2]
            self.port = line[3]
        else:
            self.user = line[0]
            self.password = line[1]
            self.ip = line[2]
            self.port = 22
        return True

    def check_host(self, line, host):
        if self.extract_host_data_from_line(line):
            print("Trying to connect to %s" % self.ip)
            host.connect_to_host()
            return True
        else:
            return False

    def prepare_data_to_write(self, access_time_trigger, location_trigger):
        host_data = str(self.user) + ' ' + str(self.password) + ' ' + str(self.ip) + ' ' + str(self.port) + ' '
        if location_trigger:
            location = str(self.get_location(self.ip)) + ' '
        else:
            location = ''
        if access_time_trigger:
            accsesstime = str(self.host_access_time)
        else:
            accsesstime = ''
        return host_data + location + accsesstime + '\n'

    def connect_to_host(self):
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(hostname=self.ip, username=self.user, password=self.password, port=self.port, timeout=3)
            print('Connected to host', self.ip, 'Access time to host:', self.access_time(), 'seconds')
            return True
        except paramiko.AuthenticationException:
            print("Authentication failed when connecting to", self.ip)
            print('Host marked as bad.')
            return False
        except ConnectionError:
            print("Could not connect to %s" % self.ip)
            return False


class List:
    def __init__(self, file):
        self.hosts_count = 0
        self.file = file

    def read_file(self, file):
        try:
            with open(file, 'r') as file:
                for line in file:
                    yield line.strip().split(' ')
        except IOError:
            print("can't read from file, IO error")
            exit(1)

    def write_file(self, file, data):
        try:
            with open(file, 'a') as file:
                file.write(data)
                self.hosts_count += 1
            return True
        except IOError:
            print("Can't write to output file, IO error")
            exit(1)


def cmd_arg_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--input-file', default='ssh_nocheck.txt')
    parser.add_argument('-o', '--output-file', default='goods.txt')
    parser.add_argument('-t', '--time', action='store_true')
    parser.add_argument('-l', '--location', action='store_true')
    return parser


def main():
    parser = cmd_arg_parser()
    namespace = parser.parse_args(sys.argv[1:])
    input_f = namespace.input_file
    output_f = namespace.output_file
    access_time_trigger = namespace.time
    location_trigger = namespace.location
    output_list = List(output_f)
    input_list = List(input_f)
    host = Host()
    current_line_count = 0
    hosts_count_incoming = host.hosts_counter(input_list)
    print('Found', hosts_count_incoming)
    for line in input_list.read_file(input_list.file):
        current_line_count += 1
        print('handling line#', current_line_count)
        check_result = host.check_host_data(line)
        if check_result:
            host.extract_host_data_from_line(line, check_result)
            connection = host.connect_to_host()
            if connection:
                prepare_data = host.prepare_data_to_write(access_time_trigger, location_trigger)
                write_line = output_list.write_file(output_list.file, prepare_data)
                if write_line:
                    print('recorded host#', current_line_count, 'of', input_list.hosts_count)
    print('From', input_list.hosts_count, 'source hosts, filtered', input_list.hosts_count - output_list.hosts_count,
          'bad hosts.', 'Passed the test:', output_list.hosts_count,
          'hosts')


if __name__ == "__main__":
    main()
 

darklight

Green Team
18.10.2018
45
72
BIT
2
Видимо никто не воспользовался скриптом, потому как в боевых условиях при работе с реальным списком обнаружились проблемы с подключенной библиотекой paramiko. Проверил работу на Whonix с Python 3.5 с небольшим списком на 176 хостов справился, правда долго работает из-за того, что однопоточный. В консоли вылетают обработвнные исключения от paramiko, это победить не смог, но работе скрипта не мешают.
Python:
#!/usr/bin/python

import paramiko
import sys
import argparse
import geoip2.database
import socket
import os


class Host:
    def __init__(self):
        self.user = None
        self.password = None
        self.ip = None
        self.port = None
        self.location = None
        self.host_access_time = 0

    @staticmethod
    def check_availability(ip, port):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(2)
        try:
            connection = s.connect((ip, port))
            if connection != 0:
                print('Host', ip, 'is available:', port, "is open.")
                s.close()
                return True
        except ConnectionError:
            print('Connection error')
            return False

    def get_location(self, ip):
        reader = geoip2.database.Reader('GeoLite2-Country.mmdb')
        response = reader.country(ip)
        return response.country.names['en']

    def hosts_counter(self, input_list):
        print('Counting host in file:', input_list.file)
        for line in input_list.read_file(input_list.file):
            input_list.hosts_count += 1
        return input_list.hosts_count

    def check_host_data(self, line):
        print('Checking data of host', line[2])
        list_len = len(line)
        if list_len == 4 or list_len == 3 and line[2].find(".") > 1:
            return True
        else:
            print('no valid data in line')
            return False

    def extract_host_data_from_line(self, line, check_result):
        if check_result == 4:
            self.user = line[0]
            self.password = line[1]
            self.ip = line[2]
            self.port = line[3]
        else:
            self.user = line[0]
            self.password = line[1]
            self.ip = line[2]
            self.port = 22

    def check_host(self, line, host):
        if self.extract_host_data_from_line(line):
            print("Trying to connect to %s" % self.ip)
            host.connect_to_host()
            return True
        else:
            return False

    def prepare_data_to_write(self, location_trigger):
        host_data = str(self.user) + ' ' + str(self.password) + ' ' + str(self.ip) + ' ' + str(self.port) + ' '
        if location_trigger:
            location = str(self.get_location(self.ip)) + ' '
        else:
            location = ''
        return host_data + location + '\n'

    def execute_command(self, client):
        stdin, stdout, stderr = client.exec_command('ls -l')
        data = stdout.read()
        if data:
            print('shell available')
            return True

    def connect_to_host(self):
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        print('Try to connect', self.ip)
        try:
            client.connect(hostname=self.ip, username=self.user, password=self.password, port=self.port, timeout=2,
                           allow_agent=False, look_for_keys=False, banner_timeout=120)
            print('Connected')
            responce = self.execute_command(client)
            if responce:
                client.close()
                return True
            else:
                return False
        except paramiko.AuthenticationException:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print("Authentication failed when connecting")
            print('Host marked as bad')
            sys.stderr = sys.__stderr__
            return False
        except paramiko.ssh_exception.SSHException as e:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print('Error reading SSH protocol banner')
            print('Host marked as bad')
            sys.stderr = sys.__stderr__
            return False
        except paramiko.ssh_exception.NoValidConnectionsError as e:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print('SSH transport is not ready...')
            print('Host marked as bad')
            return False



class List:
    def __init__(self, file):
        self.hosts_count = 0
        self.file = file

    def read_file(self, file):
        try:
            with open(file, 'r') as file:
                for line in file:
                    yield line.strip().split(' ')
        except IOError:
            print("can't read from file, IO error")
            exit(1)

    def write_file(self, file, data):
        try:
            with open(file, 'a') as file:
                file.write(data)
                self.hosts_count += 1
            return True
        except IOError:
            print("Can't write to output file, IO error")
            exit(1)


def cmd_arg_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--input-file', default='ssh_nocheck.txt')
    parser.add_argument('-o', '--output-file', default='goods.txt')
    parser.add_argument('-l', '--location', action='store_true')
    return parser


def main():
    parser = cmd_arg_parser()
    namespace = parser.parse_args(sys.argv[1:])
    input_f = namespace.input_file
    output_f = namespace.output_file
    location_trigger = namespace.location
    output_list = List(output_f)
    input_list = List(input_f)
    host = Host()
    current_line_count = 0
    hosts_count_incoming = host.hosts_counter(input_list)
    print('Found', hosts_count_incoming)
    for line in input_list.read_file(input_list.file):
        current_line_count += 1
        print('handling line#', current_line_count)
        check_result = host.check_host_data(line)
        if check_result:
            host.extract_host_data_from_line(line, check_result)
            available = host.check_availability(host.ip, int(host.port))
            if available:
                # sys.stderr = os.devnull
                connection = host.connect_to_host()
                # sys.stderr = sys.__stderr__
                if connection:
                    prepare_data = host.prepare_data_to_write(location_trigger)
                    write_line = output_list.write_file(output_list.file, prepare_data)
                    if write_line:
                        print('recorded host#', current_line_count, 'of', input_list.hosts_count)
    print('From', input_list.hosts_count, 'source hosts, filtered', input_list.hosts_count - output_list.hosts_count,
          'bad hosts.', 'Passed the test:', output_list.hosts_count,
          'hosts')


if __name__ == "__main__":
    main()
 
P

planet17

Всякий раз когда приходит свободная минутка и вдохновение попробовать питон, натыкаюсь на большую проблему. Ничегошеньки не запускается, и не устанавливается((. И всегда решение возникших ошибок отнимает приличное время.

Господа, подскажите какая это версия, 2/3?
И что нужно установить чтобы хотя бы пройти процесс инсталяции. У меня убунту 18. Пробовал и через консоль и через Пичарм со второй вылетает на поиске версии astroid. Выбирал интерпретатор третьей вообще не мог сохранить настройки, вылетали сообщения о ошибки при попытке добавить.

При этом, например скрипты отсюда же запускаются без проблем.
 
Последнее редактирование модератором:

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
Господа, подскажите какая это версия, 2/3?
И что нужно установить чтобы хотя бы пройти процесс инсталяции.
Здесь код на 3-й версии питона. От второй легко отличить по наличию в коде скобок в print. О какой инсталляции речь? Скрипты питона не инсталлируются, а сразу запускаются.
 
  • Нравится
Реакции: planet17
P

planet17

О какой инсталляции речь? Скрипты питона не инсталлируются, а сразу запускаются.

Речь об этой команде.
> pip install -r requirements.txt
Правильно ли я понимаю, это должно запускаться из под python, то есть в консоли я сначала ввожу, python3, а затем эту команду. Не уверен как бы это дальше работало, и как создавать вэнв таким способом. И нужен ли он.

Но с вашей подачи разобрался хотя бы способом через pycharm, последний не хотел работать без этих пакетов:
python3-distutils libcurl4-openssl-dev libssl-dev python3-dev

С установкой уже смог сконфигурировать вэнв, и установить зависимости.
 

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
python3 не нужно писать, другое дело что при наличии в системе python3 и python2 одна из версий встаёт по умолчанию, и соответственно скрипты запускаются для этой версии.
Можно настроить альтернативное переключений версий в линуксе так:

ls -al /usr/bin/python* Посмотреть все установленные версии питона
смена версии по умолчанию
root@kali:~# update-alternatives --list python
update-alternatives:
ошибка: нет альтернатив для python
Описание ошибки свидетельствует, что в системе нет настроеных для Python альтернатив.
ls /usr/bin/python2* определим местонахождение бинарников 2 версии
/usr/bin/python2.7
ls /usr/bin/python3*
для 3 версии
/usr/bin/python3.6
/usr/bin/python3.7

update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
альтернативы - последняя цифра приоритет
update-alternatives --install /usr/bin/python python /usr/bin/python3.6 2
python -V
проверяем версию по умочанию
убедимся, что теперь у нас в системе в качестве альтернатив установлены две версии Python
root@kali:~# update-alternatives --list python
/usr/bin/python2.7
/usr/bin/python3.6

С этого момента мы в любое время можем переключиться на нужную версию с помощью команды
update-alternatives --config python
Выбор Путь Приор Состояние
------------------------------------------------------------
* 0 /usr/bin/python3.6 2 автоматический режим
1 /usr/bin/python2.7 1 ручной режим
2 /usr/bin/python3.6 2 ручной режим
 

Raskolnikov

Green Team
30.07.2017
67
21
BIT
0
Речь об этой команде.
> pip install -r requirements.txt
Правильно ли я понимаю, это должно запускаться из под python, то есть в консоли я сначала ввожу, python3, а затем эту команду.

Это не надо запускать из-под питона, сначала надо установить pip

sudo apt install python3-pip

Это вводить в консоли линукса:
pip3 install -r requirements.txt --user


с 2 питоном, аналогично, только без 3:
sudo apt install python-pip
pip install -r requirements.txt --user
 
  • Нравится
Реакции: dark2strike и moonz
А

Анатолий_Гость

а этот скрипт на 2.7 питоне можно запустить?
а то есть только он.
 
A

Azm9s

при запуске в 2.7 версии выдает:
python2.7 porol.py
/usr/local/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py:163: CryptographyDeprecationWarning: OpenSSL version 1.0.1 is no longer supported by the OpenSSL project, please upgrade. A future version of cryptography will drop support for it.
utils.CryptographyDeprecationWarning
Traceback (most recent call last):
File "porol.py", line 10, in <module>
client.connect(hostname=host, username=user, password=secret, port=port)
File "/usr/local/lib/python2.7/site-packages/paramiko/client.py", line 349, in connect
retry_on_signal(lambda: sock.connect(addr))
File "/usr/local/lib/python2.7/site-packages/paramiko/util.py", line 280, in retry_on_signal
return function()
File "/usr/local/lib/python2.7/site-packages/paramiko/client.py", line 349, in <lambda>
retry_on_signal(lambda: sock.connect(addr))
File "/usr/local/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 60] Operation timed out
и завершает работу.
при этом все пакеты с openssl:
root@linworks:~/work/# pip install pyOpenSSL
/usr/local/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py:163: CryptographyDeprecationWarning: OpenSSL version 1.0.1 is no longe supported by the OpenSSL project, please upgrade. A future version of cryptography will drop support for it.
utils.CryptographyDeprecationWarning
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A uture version of pip will drop support for Python 2.7.
Requirement already satisfied: pyOpenSSL in /usr/local/lib/python2.7/site-packages (19.0.0)
Requirement already satisfied: cryptography>=2.3 in /usr/local/lib/python2.7/site-packages (from pyOpenSSL) (2.7)
Requirement already satisfied: six>=1.5.2 in /usr/local/lib/python2.7/site-packages (from pyOpenSSL) (1.12.0)
Requirement already satisfied: enum34; python_version < "3" in /usr/local/lib/python2.7/site-packages (from cryptography>=2.3->pyOpenSSL) (1.1.6)
Requirement already satisfied: asn1crypto>=0.21.0 in /usr/local/lib/python2.7/site-packages (from cryptography>=2.3->pyOpenSSL) (0.24.0)
Requirement already satisfied: ipaddress; python_version < "3" in /usr/local/lib/python2.7/site-packages (from cryptography>=2.3->pyOpenSSL) (1.0.22)
Requirement already satisfied: cffi!=1.11.3,>=1.8 in /usr/local/lib/python2.7/site-packages (from cryptography>=2.3->pyOpenSSL) (1.12.3)
Requirement already satisfied: pycparser in /usr/local/lib/python2.7/site-packages (from cffi!=1.11.3,>=1.8->cryptography>=2.3->pyOpenSSL) (2.19)

root@linworks:~/work/# pip install cryptography
/usr/local/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py:163: CryptographyDeprecationWarning: OpenSSL version 1.0.1 is no longe supported by the OpenSSL project, please upgrade. A future version of cryptography will drop support for it.
utils.CryptographyDeprecationWarning
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A uture version of pip will drop support for Python 2.7.
Requirement already satisfied: cryptography in /usr/local/lib/python2.7/site-packages (2.7)
Requirement already satisfied: enum34; python_version < "3" in /usr/local/lib/python2.7/site-packages (from cryptography) (1.1.6)
Requirement already satisfied: asn1crypto>=0.21.0 in /usr/local/lib/python2.7/site-packages (from cryptography) (0.24.0)
Requirement already satisfied: ipaddress; python_version < "3" in /usr/local/lib/python2.7/site-packages (from cryptography) (1.0.22)
Requirement already satisfied: six>=1.4.1 in /usr/local/lib/python2.7/site-packages (from cryptography) (1.12.0)
Requirement already satisfied: cffi!=1.11.3,>=1.8 in /usr/local/lib/python2.7/site-packages (from cryptography) (1.12.3)
Requirement already satisfied: pycparser in /usr/local/lib/python2.7/site-packages (from cffi!=1.11.3,>=1.8->cryptography) (2.19)

root@linworks:~/work/# pip install OpenSSL
/usr/local/lib/python2.7/site-packages/cryptography/hazmat/bindings/openssl/binding.py:163: CryptographyDeprecationWarning: OpenSSL version 1.0.1 is no longe supported by the OpenSSL project, please upgrade. A future version of cryptography will drop support for it.
utils.CryptographyDeprecationWarning
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A uture version of pip will drop support for Python 2.7.
Collecting OpenSSL
ERROR: Could not find a version that satisfies the requirement OpenSSL (from versions: none)
ERROR: No matching distribution found for OpenSSL

Как сию ошибку можно исправить в данной версии python?
 

explorer

Platinum
05.08.2018
1 080
2 475
BIT
0
а этот скрипт на 2.7 питоне можно запустить?
Как сию ошибку можно исправить в данной версии python?
Парни, выше было написано - код на python 3. Разве сложно установить? На 2.7 ничего не запустится, если только поправить сам скрипт под 2.7
 
A

Azm9s

Парни, выше было написано - код на python 3. Разве сложно установить? На 2.7 ничего не запустится, если только поправить сам скрипт под 2.7
на 2.7 пришлось либу другую ставить. paramiko 1.17.1.

там она использует crypro вместо Cryptography, так как последняя ругается на openssl 1.0.1
скрипт глобально не пришлось переделывать, только строка:

except socket.error:
вместо
except ConnectionError:

да и print '' а не print()

Такой вопрос, а как можно вывести список ip адресов(у которых не подошел пароль, но ssh там работает), в отдельный список bads.txt???

установить нельзя. тут эти то либы устанавливались актом, комиссионно за подписью 12 человек, с записыванием контрольной суммы всех файлов в библиотеках.
а Вы говорите, установить 3 питон...

С позволения автора,
работает на 2.7, пишет два файла, один с рабочими адресами и паролями, а второй где ssh работает, но не подходят учетные данные.

Python:
#!/usr/bin/python
# -*- coding: utf-8 -*-


import paramiko
import sys
import argparse
import geoip2.database
import socket
import os
reload(sys)
sys.setdefaultencoding('utf8')

class Host:
    def __init__(self):
        self.user = None
        self.password = None
        self.ip = None
        self.port = None
        self.location = None
        self.host_access_time = 0
        self.off_count = 0

    @staticmethod
    def check_availability(ip, port):
        host = Host()
        #def __init__(self):
        #   self.off_count
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(2)
        try:
            connection = s.connect((ip, port))
            if connection != 0:
                print 'Адрес', ip, 'исправен:', port, "порт открыт."
                s.close()
                return True
        except socket.error:
            print 'Ошибка соединения, 22 порт не работает'
            #host = Host()
            host.off_count += 1
            print host.off_count
            return False

    def get_location(self, ip):
        #reader = geoip2.database.Reader('GeoLite2-Country.mmdb')
        #response = reader.country(ip)
        response = ''
        return response.country.names['en']

    def hosts_counter(self, input_list):
        print 'Проверка наличия файла: ', input_list.file
        for line in input_list.read_file(input_list.file):
            input_list.hosts_count += 1
        return input_list.hosts_count

    def check_host_data(self, line):
        print 'Проверка адреса', line[2]
        list_len = len(line)
        if list_len == 4 or list_len == 3 and line[2].find(".") > 1:
            return True
        else:
            print 'Проверьте исправность записи'
            return False

    def extract_host_data_from_line(self, line, check_result):
        if check_result == 4:
            self.user = line[0]
            self.password = line[1]
            self.ip = line[2]
            self.port = line[3]
        else:
            self.user = line[0]
            self.password = line[1]
            self.ip = line[2]
            self.port = 22

    def check_host(self, line, host):
        if self.extract_host_data_from_line(line):
            print "Повторное соединение с адресом: %s" % self.ip
            host.connect_to_host()
            return True
        else:
            return False

    def prepare_data_to_write(self, location_trigger):
        #host_data = str(self.user) + ' ' + str(self.password) + ' ' + str(self.ip) + ' ' + str(self.port) + ' '
        host_data = str(self.user) + ' ' + str(self.password) + ' ' + str(self.ip) + ' '
        #if location_trigger:
        #    location = str(self.get_location(self.ip)) + ' '
        #else:
        #    location = ''
        location = ''
        return host_data + location + '\n'

    def prepare_data_bad_to_write(self, location_trigger):
        #host_data = str(self.user) + ' ' + str(self.password) + ' ' + str(self.ip) + ' ' + str(self.port) + ' '
        host_data = str(self.ip) + ' '
        #if location_trigger:
        #    location = str(self.get_location(self.ip)) + ' '
        #else:
        #    location = ''
        location = ''
        return host_data + location + '\n'

    def execute_command(self, client):
        stdin, stdout, stderr = client.exec_command('hostname')
        data = stdout.read()
        if data:
            print 'Доступ получен'
            return True

    def connect_to_host(self):
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        print 'Попытка соединения с', self.ip
        try:
            client.connect(hostname=self.ip, username=self.user, password=self.password, port=self.port, timeout=2,
                           allow_agent=False, look_for_keys=False, banner_timeout=120)
            print 'Соединились'
            responce = self.execute_command(client)
            if responce:
                client.close()
                return True
            else:
                return False
        except paramiko.AuthenticationException:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print 'Авторизация не пройдена'
            print 'Адрес помечен как неисправный'
            sys.stderr = sys.__stderr__
            return False
        except paramiko.ssh_exception.SSHException as e:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print('Error reading SSH protocol banner')
            print('Host marked as bad')
            sys.stderr = sys.__stderr__
            return False
        except paramiko.ssh_exception.NoValidConnectionsError as e:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print('SSH transport is not ready...')
            print('Host marked as bad')
            return False



class List:
    def __init__(self, file):
        self.hosts_count = 0
        self.file = file

    def read_file(self, file):
        try:
            with open(file, 'r') as file:
                for line in file:
                    yield line.strip().split(' ')
        except IOError:
            print("can't read from file, IO error")
            exit(1)

    def write_file(self, file, data):
        try:
            with open(file, 'a') as file:
                file.write(data)
                self.hosts_count += 1
            return True
        except IOError:
            print("Can't write to output file, IO error")
            exit(1)


def cmd_arg_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('-i', '--input-file', default='preout/spisok_in.txt')
    parser.add_argument('-o', '--output-file', default='preout/spikok_gods.txt')
    parser.add_argument('-b', '--bad-file', default='preout/spisok_bads.txt')
    parser.add_argument('-l', '--location', action='store_true')
    return parser


def main():
    parser = cmd_arg_parser()
    namespace = parser.parse_args(sys.argv[1:])
    input_f = namespace.input_file
    output_f = namespace.output_file
    output_bad_f = namespace.bad_file
    location_trigger = namespace.location
    output_list = List(output_f)
    output_bad= List(output_bad_f)
    input_list = List(input_f)
    host = Host()
    current_line_count = 0
    hosts_count_incoming = host.hosts_counter(input_list)
    print 'Найдено записей: ', hosts_count_incoming
    for line in input_list.read_file(input_list.file):
        current_line_count += 1
        print 'Проверяется запись:', current_line_count
        check_result = host.check_host_data(line)
        if check_result:
            host.extract_host_data_from_line(line, check_result)
            available = host.check_availability(host.ip, int(host.port))
            if available:
                # sys.stderr = os.devnull
                connection = host.connect_to_host()
                # sys.stderr = sys.__stderr__
                if connection:
                    prepare_data = host.prepare_data_to_write(location_trigger)
                    write_line = output_list.write_file(output_list.file, prepare_data)
                    if write_line:
                        print 'Адрес ', current_line_count, 'из', input_list.hosts_count, ' записан в файл как исправный'
                else:
                    prepare_data = host.prepare_data_bad_to_write(location_trigger)
                    write_line = output_bad.write_file(output_bad.file, prepare_data)
    print 'Всего проверено:', input_list.hosts_count, 'адресов'
    print 'Не прошло: ', input_list.hosts_count - output_list.hosts_count,\
          'адресов.', 'Из них отключены: ', host.off_count, 'адрес. Не верный пароль на: ', \
          input_list.hosts_count - output_list.hosts_count - host.off_count, 'адресах'
    print 'Исправны: ', output_list.hosts_count,\
          'адресов'


if __name__ == "__main__":
    main()

правда, не работает счетчик отключенных хостов, все время 1 показывает в одном месте и 0 в другом.... :)
но может он и не нужен кому-то))
 
  • Нравится
Реакции: centr и larchik
A

Azm9s

счетчик победил:

Python:
        except socket.error:
            print 'Ошибка соединения, 22 порт не работает'
            #host = Host()
            self.off_count += 1
            #print self.off_count
            return False
print 'Не прошло: ', input_list.hosts_count - output_list.hosts_count,\
          'адресов.', 'Из них отключены: ', host.off_count, 'адрес. Не верный пароль на: ', \
          input_list.hosts_count - output_list.hosts_count - host.off_count, 'адресах'
вместо host.off_count += 1, там где идет расчет. а где просто вывод: host.off_count

подскажите, как сделать, чтобы:
1. как переделать тут команду под разные варианты?
Python:
    def execute_command(self, client):
        stdin, stdout, stderr = client.exec_command('hostname')
        data = stdout.read()
        if data:
            print 'Доступ получен'
            return True
а то не везде есть команды ls -l, uptime, hostname, id....
и этот список обширен :(

2. как обработать секции:
Python:
        except paramiko.AuthenticationException:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print 'Авторизация не пройдена'
            print 'Адрес помечен как неисправный'
            sys.stderr = sys.__stderr__
            return False
        except paramiko.ssh_exception.SSHException as e:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print('Error reading SSH protocol banner')
            print('Host marked as bad')
            sys.stderr = sys.__stderr__
            return False
        except paramiko.ssh_exception.NoValidConnectionsError as e:
            # sys.stderr.write("Exc: " + str(sys.exc_info()[0]) + "\n")
            print('SSH transport is not ready...')
            print('Host marked as bad')
            return False

чтобы тоже можно было записать эти адреса в spisok_bads.txt
 
  • Нравится
Реакции: larchik
N

NexuS

1. как переделать тут команду под разные варианты?
Python:
def execute_command(self, client):
    comand = ('ls -l', 'uptime', '.....', 'hostname', 'id')#список разных вариантов
    for cmd in comand:
        stdin, stdout, stderr = client.exec_command(cmd)
        data = stdout.read()
        if data:
            print 'Доступ получен'
            return True

2. как обработать секции:
чтобы тоже можно было записать эти адреса в spisok_bads.txt

Перед каждым return вызывай функцию записи в файл spisok_bads.txt и передавай в него self.ip + наверное будет полезен и комментарий из исключения.
 
  • Нравится
Реакции: Azm9s

pp11

Green Team
16.09.2018
201
82
BIT
1
Взял на заметку.
Сегодня как раз написал для себя чекер. Но только использую библиотеку pexpect. В общей сумме ~20 строчек кода и полностью рабочий чекер.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!