Автоматизация Cisco IOU из консоли

в 7:36, , рубрики: Cisco, IOU, linux, метки: ,

Долго раздумывал о публикации статьи, и когда всё же решился, то посвятил ее интересному эмулятору Cisco IOU. А точнее — этапу запуска любой сложной схемы, не прибегая к графическим средствам, таким как GNS3 или IOU Web.

Не буду выдумывать велосипед и за основу возьму статью @Avtandiko «Поднимаем упрощенную провайдерскую сеть дома», тем более в комментариях автора просили поделиться стендом.

Автором использовались образы i86bi_linux-adventerprisek9-ms.152-4.M1 и i86bi_linux_l2-ipbasek9-ms.jan24-2013-B, но, на самом деле, не в этом суть. Я бы хотел предложить альтернативный вариант, к сожалению, работающий только в ArchLinux. Это собрать свой пакет IOU.

Из преимуществ: нет необходимости таскать с собой образы, унифицированный подход к запуску разных стендов. Не буду подробно рассказывать, как собирать пакеты в ArchLinux, в интернете хватает информации по этому поводу. Приведу лишь PKBUILD и install. Дополнительные компоненты iou2net.pl, CiscoIOUKeygen.py, IOUsniffer, wrapper-linux находятся в свободном доступе.

PKBUILD

pkgname=iou
pkgver=1.2
pkgrel=1
pkgdesc=«Cisco IOU»
arch=(«any»)
url=«www.cisco.com»
license=(«custom»)
depends=(«libpcap»
«cryptsetup»
«lib32-openssl»
«perl-net-pcap»)
options=(«emptydirs»)
install="${pkgname}.install"
source=("${pkgname}.install"
«iou2net.pl»
«CiscoIOUKeygen.py»
«IOUsniffer.tar.gz»
«wrapper-linux.tar.gz»
«i86bi_linux-adventerprisek9-ms.152-2.15.T»
«i86bi_linux_l2-ipbasek9-ms.jan24-2013-team_track»)

build() {
cd "${srcdir}/IOUsniffer" && make || return 1
cd "${srcdir}/wrapper-linux" && make || return 1
}

package() {
install -Dm 0755 "${srcdir}/iou2net.pl" "${pkgdir}/usr/bin/iou-live"
install -Dm 0755 "${srcdir}/CiscoIOUKeygen.py" "${pkgdir}/usr/bin/iou-keygen"
install -Dm 0755 "${srcdir}/IOUsniffer/iousniff" "${pkgdir}/usr/bin/iou-sniff"
install -Dm 0755 "${srcdir}/wrapper-linux/wrapper-linux" "${pkgdir}/usr/bin/iou-wrapper"
install -Dm 0755 "${srcdir}/i86bi_linux-adventerprisek9-ms.152-2.15.T" "${pkgdir}/usr/bin/iou-router"
install -Dm 0755 "${srcdir}/i86bi_linux_l2-ipbasek9-ms.jan24-2013-team_track" "${pkgdir}/usr/bin/iou-switch"
install -dm 0755 "${pkgdir}/usr/lib32/"
ln -s "/usr/lib32/libcrypto.so.1.0.0" "${pkgdir}/usr/lib32/libcrypto.so.4"
}

md5sums=('SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP'
'SKIP')

iou.install
post_install() {
grep xml.cisco.com /etc/hosts > /dev/null
if [ $? -ne 0 ]
then
echo '127.0.0.127 xml.cisco.com' >> /etc/hosts
fi
/usr/bin/iou-keygen
}

post_upgrade() {
grep xml.cisco.com /etc/hosts > /dev/null
if [ $? -ne 0 ]
then
echo '127.0.0.127 xml.cisco.com' >> /etc/hosts
fi
}

post_remove() {
grep xml.cisco.com /etc/hosts > /dev/null
if [ $? -ne 1 ]
then
sed -i '/xml.cisco.com/d' /etc/hosts
fi
}

Далее перейдем к схеме. Напомню (изображение схемы сети взято из вышеупомянутой статьи):

Автоматизация Cisco IOU из консоли - 1

Самый скрупулезный в этом процессе этап — правильно составить NETMAP.

NETMAP
1:0/1 3:0/1 1
2:0/1 3:0/2 1
2:0/3 5:1/1 1
2:0/2 7:0/0 1
2:0/0 6:0/1 1
2:1/0 15:0/0 1
6:1/0 15:0/1 1
5:1/0 6:0/2 1
6:0/3 7:0/1 1
6:0/0 8:0/0 1
3:0/0 4:0/0 1
3:0/3 5:0/0 1
4:0/2 5:1/2 1
5:0/3 7:1/0 1
7:0/2 8:0/2 1
8:0/1 12:0/0 1
4:0/1 9:0/0 1
5:0/1 10:0/0 1
5:0/2 11:0/0 1
7:0/3 11:0/1 1
9:0/1 10:0/2 1
9:0/2 13:0/0 1
10:0/1 13:0/1 1
11:0/2 14:0/0 1

В принципе, ничего нового, за исключением цифры «1» в конце каждой строки. Она необходима для IOUSneffer, указывает на тип соединения. В данном случае Ethernet.

Ну и самое интересное в конце — сам скрипт запуска стенда:

run.sh

#!/bin/bash
WRAPPER="/usr/bin/iou-wrapper"
ROUTER="/usr/bin/iou-router"
SWITCH="/usr/bin/iou-switch"
IOUSNIFF="/usr/bin/iou-sniff"
DUMPDIR="./dump"
DUMPDIRTMP="${DUMPDIR}/tmp"
DUMPFILE="${DUMPDIR}/dump-$(date +%F-%T).pcap"
DELAY="5"
MODE=${1:-"--help"}
#         Name     Type   ID     Port      Serial  Ethernet
DEVICES=( "R-01"   "R"    "1"    "10001"   "0"     "1"
          "R-02"   "R"    "2"    "10002"   "0"     "2"
          "R-03"   "R"    "3"    "10003"   "0"     "1"
          "R-04"   "R"    "4"    "10004"   "0"     "1"
          "R-05"   "R"    "5"    "10005"   "0"     "2"
          "R-06"   "R"    "6"    "10006"   "0"     "2"
          "R-07"   "R"    "7"    "10007"   "0"     "2"
          "R-08"   "R"    "8"    "10008"   "0"     "1"
          "R-09"   "R"    "9"    "10009"   "0"     "1"
          "R-10"   "R"    "10"   "10010"   "0"     "1"
          "R-11"   "R"    "11"   "10011"   "0"     "1"
          "SW-12"  "S"    "12"   "10012"   "0"     "1"
          "SW-13"  "S"    "13"   "10013"   "0"     "1"
          "SW-14"  "S"    "14"   "10014"   "0"     "1"
          "R-15"   "R"    "15"   "10015"   "0"     "1"
)

start-iou() {
    for ((index=0; index < ${#DEVICES[@]}/6; index++))
    do
        if [ "X_${DEVICES[${index}*6+1]}" == "X_R" ]
        then
            ${WRAPPER} -m ${ROUTER} -p ${DEVICES[${index}*6+3]} -- 
                                    -s ${DEVICES[${index}*6+4]} 
                                    -e ${DEVICES[${index}*6+5]} ${DEVICES[${index}*6+2]} &> /dev/null &
        else
            ${WRAPPER} -m ${SWITCH} -p ${DEVICES[${index}*6+3]} -- 
                                    -s ${DEVICES[${index}*6+4]} 
                                    -e ${DEVICES[${index}*6+5]} ${DEVICES[${index}*6+2]} &> /dev/null &
        fi
    done
}

start-konsole() {
    touch ./tabs
    for ((index=0; index < ${#DEVICES[@]}/6; index++))
    do
        echo "title: ${DEVICES[${index}*6]};; command: telnet localhost ${DEVICES[${index}*6+3]}" >> ./tabs
    done
    konsole --tabs-from-file ./tabs &> /dev/null
    rm ./tabs &> /dev/null
}

reset-konsole() {
    for ((index=0; index < ${#DEVICES[@]}/6; index++))
    do
        sudo kill -SIGHUP $(fuser -n tcp ${DEVICES[${index}*6+3]} 2>&1 | awk '{print $2}')
    done
}

start-sniff() {
    [ -d ${DUMPDIR} ] || mkdir -p ${DUMPDIR} &> /dev/null
    mkdir -p "${DUMPDIRTMP}" &> /dev/null
    ${IOUSNIFF} -f -o -i /tmp/netio$(id -u) -n ./NETMAP -s ${DUMPDIRTMP} &> /dev/null &
}

stop() {
    ps -e | grep "${1}" | awk '{ print $1 }' | xargs sudo kill "-${2}" &> /dev/null
}

case "${MODE}" in
  --start)
    start-iou
    sleep ${DELAY}
    start-konsole
  ;;

  --stop)
    stop "iou" "SIGKILL"
  ;;

  --start-iou)
    start-iou
  ;;

  --start-konsole)
    start-konsole
  ;;

  --reset-konsole)
    reset-konsole
  ;;

  --start-sniff)
    start-sniff
  ;;

  --stop-sniff)
    stop "iou-sniff" "SIGINT"
    fdupes -d -N ${DUMPDIRTMP} &> /dev/null
    mergecap -w ${DUMPFILE} ${DUMPDIRTMP}/*.pcap
    rm -rf ${DUMPDIRTMP} &> /dev/null
  ;;

  --help|*)
    echo -e "nUsage: ${0} [OPTIONS]"
    echo -e "nOPTIONS:n"
    echo -e "t--start t- Start"
    echo -e "t--stop tt- Stop"
    echo -e "t--start-iou t- Start IOU"
    echo -e "t--start-sniff t- Start Sniff"
    echo -e "t--stop-sniff t- Stop Sniff"
    echo -e "t--start-konsole - Start konsole"
    echo -e "t--reset-konsole - Reset konsole"
    echo -e "t--help tt- Helpn"
  ;;
esac

Представленный скрипт настроен на работу с текущем стендом. В случае использования его в другой схеме необходимо только корректно заполнить массив DEVICES:

#         Name     Type   ID     Port      Serial  Ethernet
DEVICES=( "R-01"   "R"    "1"    "10001"   "0"     "1"
          "R-02"   "R"    "2"    "10002"   "0"     "2"
          "R-03"   "R"    "3"    "10003"   "0"     "1"
          "R-04"   "R"    "4"    "10004"   "0"     "1"
          "R-05"   "R"    "5"    "10005"   "0"     "2"
          "R-06"   "R"    "6"    "10006"   "0"     "2"
          "R-07"   "R"    "7"    "10007"   "0"     "2"
          "R-08"   "R"    "8"    "10008"   "0"     "1"
          "R-09"   "R"    "9"    "10009"   "0"     "1"
          "R-10"   "R"    "10"   "10010"   "0"     "1"
          "R-11"   "R"    "11"   "10011"   "0"     "1"
          "SW-12"  "S"    "12"   "10012"   "0"     "1"
          "SW-13"  "S"    "13"   "10013"   "0"     "1"
          "SW-14"  "S"    "14"   "10014"   "0"     "1"
          "R-15"   "R"    "15"   "10015"   "0"     "1"
)

Одномерный массив DEVICES состоит из шести псевдостолбцов (такой подход прижился у меня еще со времен использования C, не исключаю более изящного решения задачи).

  1. Name — Условное название устройства, которое будет использоваться при подписи вкладок konsole;
  2. Type — Тип устройства: R — маршрутизатор, S — коммутатор;
  3. ID — Идентификатор устройства, используемый также в NETMAP;
  4. Port — Номер порта, по которому посредством telnet можно подключиться к консоли устройства;
  5. Serial — Количество карт, установленных в устройство с портами Serial;
  6. Ethernet — Количество карт, установленных в устройство с портами Ethernet.

В заключении статьи раскрою опции старта скрипта:

  1. --start — Полный старт стенда с одновременным подключением к консоли;
  2. --stop — Полное выключение стенда;
  3. --start-iou — Запуск всех устройств без дополнительного подключения к ним по консоли;
  4. --start-konsole — Подключение ко всем устройствам по консоли;
  5. --reset-konsole — В случае зависания консоли, а такое иногда бывает. Можно посредством текущей опции сбросить все подключения без перезагрузки устройств;
  6. --start-sniff — Когда возникает необходимость поснифферить, то необходимо запустить скрипт с данной опцией. Выдержать период времени, в течении которого производится захват пакетов. Далее необходимо остановить захват пакетов опцией --stop-sniff и вы получите полный дамп вашей сети в папке ./dump;
  7. --stop-sniff — Остановить режим захвата пакетов.

Автор: artes1101

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js