Show version and haiku, но не только: ищем все скрытые команды Junos

Всем привет! Эта статья — о скрытых командах операционной системы Junos. Тем, кто работал с оборудованием Juniper под управлением ОС Junos (сюда относятся серии MX, SRX, EX, QFX, T, J, и многие другие) наверняка известно, что кроме «официальных» (документированных) команд в системе имеются и недокументированные. Их особенность в том, что они не видны в интерфейсе командной строки по контекстной подсказке (это когда вводишь вопросительный знак) и для них не работает автозаполнение, то есть команду нужно знать и ввести полностью (все буквы). Видимо, самая известная (и самая бесполезная) из таких команд — show version and haiku, выдающая «японское» трехстишие о жизни сетевых инженеров.

Скрытых команд, на самом деле, много. Вендор нигде не приводит их полного списка, но, например, на официальном форуме Juniper имеется прилепленный топик с довольно большим набором. Так что производитель не возражает против использования нами таких команд, просто на них не дается никакой гарантии — может работать, а может и положить ваше оборудование.

В этой статье я расскажу о том, как можно получить список всех скрытых команд Junos операционного режима, в пределах какой-то начальной ветки. Метод основан на довольно простом наблюдении, но гуглением мне не удалось найти свидетельств того, что вопрос раньше ставился в такой форме. Пример скрипта на Python прилагается.

ИдеяОсновная идея подхода очень проста, но чтобы ее уяснить, все-таки хорошо иметь доступ к CLI какого-либо Junos-устройства.Рассмотрим, например, команду «show version». Если мы вводим «show version a» (в конце — всегда жмем Enter), то вывод команды — такой:

lab@jsrxA-1> show version a ^ syntax error. А если «show version с», то lab@jsrxA-1> show version c ^ syntax error, expecting . В первом случае имеется скрытое продолжение (and haiku), во втором — нет. Как видно, реакция CLI при наличии скрытого продолжения отличается двумя аспектами: «syntax error.» вместо «syntax error, expecting ‹command›.»; шляпка (a.k.a. циркумфлекс) стоит под следующей позицией строки. Соответственно, перебирая буквы одну за другой (хоть и вручную, но лучше автоматизировать), мы можем найти спрятанные команды — Junos сам их подсказывает, хоть и не так явно, как с обычными командами! Предварительные замечания Прежде чем писать скрипт, я должен предупредить читателей, что скрытые команды были скрыты разработчиком не просто так. Некоторые из них могут нарушить работу устройства, повредить файловую систему, и т.п. Поэтому их, даже по одной, следует использовать с большой осторожностью. В нашем случае, когда делается поиск перебором, это предостережение возводится в такую степень, что ни в коем случае не следует запускать подобный скрипт на обрабатывающем пользовательский трафик оборудовании. Ведь мы перебираем все команды, среди которых могут содержаться и file delete, и request system zeroize, и restart routing, и еще много чего. Так что играйтесь только с неподключенными к сети железками, которые не жалко убить, а лучше с виртуальным SRX (a.k.a. Firefly Perimeter).Также следует пояснить, что хотя у Junos имеется очень удобный и продвинутый, основанный на XML, API, его использование для данной задачи не представляется возможным, так как наш подход поиска команд основан на особенностях работы CLI. Поэтому будем открывать обычную telnet-сессию, давать команды и парсить текстовый вывод.

В данной статье я ограничусь поиском команд операционного режима. Есть еще конфигурация, и в ней тоже много всего интересного припрятано (тот же commit full). Поиск скрытых команд там можно проводить аналогично.

Алгоритм Итак, начиная с определенной команды (commandStart в скрипте) мы будем обходить все возможные варианты команд, добавляя каждый раз по символу (из массива alphabet) и вводя Enter. Вывод, присылаемый Junos в ответ, может быть следующим: Ругань про «syntax error.» (и при этом шляпка указывает на наличие продолжения команды) — признак наличия hidden-команды, перебираем дальше, добавляя новые символы. Ругань про «syntax error, expecting ‹command›.» —здесь необходимо анализировать положение шляпки. Если она на текущей букве, как выше в примере «show version c», то далее не идем, скрытых команд нет.Если же она указывает на продолжение команды, как здесь: lab@jsrxA-1> show version and ^ syntax error, expecting . то в этом случае команда имеет продолжение и необходимо перебирать дальше (команда тут может быть скрытой или нет, в зависимости от предыстории). Просто вывод команды, без ругани про синтаксические ошибки, но возможно с руганью про двусмысленный (ambiguous) ввод, например как здесь: lab@jlab-Firefly-3> show chassis cluster i ^ 'i' is ambiguous. Possible completions: interfaces Display chassis cluster interfaces ip-monitoring Display IP monitoring related information В этом случае перебор необходимо продолжать, т.к. далее может содержаться скрытая команда (в данном случае, show chassis cluster information). Также необходимо учитывать, что выводы некоторых команд могут занимать несколько экранов, что приводит к выдаче приглашения »---(more)---». В этом случае просто шлем пробел.Скрипт Собственно, вот он.Скрипт (Python 3) import telnetlib import re

HOST = »192.168.65.161» user = «lab» password = «lab123» commandStart = «show version » # note space at the end

alphabet = «abcdefghijklmnopqrstuvwxyz-1234567890.» PAUSE = 3

def SearchCommands (cmd, on_hidden_now=False): for nChar in range (0, len (alphabet)): char = str (alphabet[nChar]) tn.write (cmd.encode ('ascii') + char.encode ('ascii') + b»\n») totData=» finished = False while (not finished): inpData = tn.read_until (prompt.encode ('ascii'), PAUSE) totData = totData + inpData.decode ('ascii') if »---(more» in inpData.decode ('ascii'): tn.write (b» ») else: finished = True

cmdNext = cmd + str (char) synt_error_exp_cmd = False synt_error_period = False if «syntax error, expecting .» in totData: synt_error_exp_cmd = True if «syntax error.» in totData: synt_error_period = True if not (synt_error_exp_cmd or synt_error_period): # normal output or ambiguity if on_hidden_now: print («hidden command >> » + cmdNext) else: SearchCommands (cmdNext, on_hidden_now) # i.e. False else: l = re.findall (' *\^', totData) lenToHat = len (l[len (l)-1]) if synt_error_period: if lenToHat > lenPrompt + len (cmdNext): SearchCommands (cmdNext, True) # Hidden command in progress if synt_error_exp_cmd: if (lenToHat == 2 + lenPrompt + len (cmdNext)): if on_hidden_now: print («hidden command >> » + cmdNext + » (incomplete)») # else: print («Entering:» + cmdNext) SearchCommands (cmdNext+» », on_hidden_now) if lenToHat > 2 + lenPrompt + len (cmdNext): SearchCommands (cmdNext, on_hidden_now)

tn = telnetlib.Telnet (HOST) tn.read_until (b«login:») tn.write (user.encode ('ascii') + b»\n») tn.read_until (b«Password:») tn.write (password.encode ('ascii') + b»\n»)

loginText = tn.read_until (b»> »).decode ('ascii') prompt = re.search (».*@.*», loginText).group () print («Working with prompt = » + prompt) lenPrompt = len (prompt) SearchCommands (commandStart)

Примеры работы: Запуск для ветки show version hidden command >> show version and (incomplete)hidden command >> show version and blamehidden command >> show version and haikuhidden command >> show version extensivehidden command >> show version forwarding-contexthidden command >> show version invoke-on (incomplete)hidden command >> show version invoke-on ahidden command >> show version invoke-on ohidden command >> show version no-forwardinghidden command >> show version scc-dont-forwardhidden command >> show version sdk

Запуск для ветки show chassis hidden command >> show chassis accurate-statisticshidden command >> show chassis beaconhidden command >> show chassis broadcomhidden command >> show chassis cfebhidden command >> show chassis ciphidden command >> show chassis clockshidden command >> show chassis cluster ethernet-switching (incomplete)hidden command >> show chassis cluster informationhidden command >> show chassis cluster ip-monitoring (incomplete)hidden command >> show chassis craft-interfacehidden command >> show chassis customer-idhidden command >> show chassis ethernet-switchhidden command >> show chassis fabric (incomplete)hidden command >> show chassis fchiphidden command >> show chassis febhidden command >> show chassis fpc-feb-connectivityhidden command >> show chassis hsl (incomplete)hidden command >> show chassis hsrhidden command >> show chassis hss (incomplete)hidden command >> show chassis hsthidden command >> show chassis in-service-upgradehidden command >> show chassis ioc-npc-connectivityhidden command >> show chassis lccshidden command >> show chassis message-statistics (incomplete)hidden command >> show chassis message-statistics ihidden command >> show chassis network-serviceshidden command >> show chassis nonstop-upgradehidden command >> show chassis power-budget-statisticshidden command >> show chassis psdhidden command >> show chassis redundancy (incomplete)hidden command >> show chassis redundant-power-systemhidden command >> show chassis scbhidden command >> show chassis sfmhidden command >> show chassis sibshidden command >> show chassis spmbhidden command >> show chassis ssbhidden command >> show chassis synchronizationhidden command >> show chassis tfebhidden command >> show chassis timershidden command >> show chassis usb (incomplete)hidden command >> show chassis zones

Запуск для ветки show security idp (на SRX240) hidden command >> show security idp active-policyhidden command >> show security idp application-ddos (incomplete)hidden command >> show security idp application-identification (incomplete)hidden command >> show security idp detector (incomplete)hidden command >> show security idp detector ahidden command >> show security idp detector chidden command >> show security idp detector phidden command >> show security idp ips-cachehidden command >> show security idp logical-system (incomplete)

Как видно, скрипт помечает некоторые команды как incomplete — это те, у которых предполагается продолжение. В случае, если продолжение команды Junos уже не прячет, такая команда далее тоже находится скриптом, но выдается в сокращенном виде (show chassis message-statistics i — это show chassis message-statistics ipc).Цели обработать скриптом все возможные ошибки и ситуации не ставилось, поэтому если у вас в дескрипшенах интерфейсов содержится строка про synax error, на которую скрипт реагирует, или включен логгинг в терминал, логика работы может нарушиться.

Еще одной проблемой являются команды, принимающие на вход любое имя, например show interfaces AnyInterfaceNameIsOKHere (в отсутствии такого интерфейса выдается ошибка, другие подобные команды могут не выдавать ничего). По понятной причине, скрипт при натравливании его на show interfaces, вылетает с ошибкой про maximum recursion depth exceeded. Зато поиск с commandStart = «show interfaces ge-0/0/0 » работает нормально:

Запуск для show interfaces ge-0/0/0 hidden command >> show interfaces ge-0/0/0 forwarding-contexthidden command >> show interfaces ge-0/0/0 ifd-indexhidden command >> show interfaces ge-0/0/0 ifl-indexhidden command >> show interfaces ge-0/0/0 instancehidden command >> show interfaces ge-0/0/0 no-forwardinghidden command >> show interfaces ge-0/0/0 scc-dont-forward

Заключение Надо понимать, что значительная часть hidden-команд скрыты по причине того, что не поддерживаются (или не имеют смысла) на данном оборудовании или в данной версии софта. Многие из них бесполезны, тем не менее, среди них встречаются и «самородки» (например, show chassis cluster information). Поскольку я работаю инструктором по Juniper, то довольно часто приходится слышать от студентов вопрос — где взять список всех скрытых команд. Так что буду теперь всех отсылать к этой статье. Надеюсь, что какая-то польза от данного рецепта кому-то будет.

© Habrahabr.ru