Python: Combine NetIfaces, Scapy and IPAddress to find local connected network

You got the task to generate a list of IP-Networks connected to LAN „VirtualBox Host-Only Network“. There might be more than one IP-Network.

Use Scapy to crawl through all Interfaces and get the human-readable interface name [only required for windows users]. Use NetIfaces to get a list of IP-Addresses connected to this interface. Use IPAddress to calculate the IP-Network(s) directly connected.

! multiple IPs per Interface supporte
!
from netifaces import AF_INET, AF_INET6, AF_LINK
import netifaces

from scapy.all import *

import ipaddress


if_name = "VirtualBox Host-Only Network"
if_id = ""
if_inet = []

for i in ifaces.data.keys():
  iface = ifaces.data[i]
  wname = iface.data['netid']
  if wname == if_name:
    if_id = i
    addresses = netifaces.ifaddresses(i)
    if AF_INET in addresses:
      for addr in netifaces.ifaddresses(i)[AF_INET]:
        print(addr)
        ipaddr = ipaddress.ip_interface(addr["addr"]+"/"+addr["netmask"])
        ipnetwork = ipaddr.network
        print(ipaddr,ipnetwork)
        if_inet.append(ipnetwork)

print("NAME: {0}\nIP: {1}\nID: {2}".format(if_name,if_inet,if_id))

In my case, only one subnet is directly connected:

  • 192.168.56.0/24
...
{'addr': '192.168.56.1', 'netmask': '255.255.255.0', 'broadcast': '192.168.56.255'}
192.168.56.1/24 192.168.56.0/24
>>> print("NAME: {0}\nIP: {1}\nID: {2}".format(if_name,if_inet,if_id))
NAME: VirtualBox Host-Only Network
IP: [IPv4Network('192.168.56.0/24')]
ID: {D30DEC05-D495-4DA1-81F1-42B07885B0EB}
>>>

Python netifaces and scapy: Getting meaningful Interface-names and full IP-Adresses-/Netmask-Information

Using Windows:

  • scapy reads:
    • meaningful interface-names
    • ip-address
    • but no netmask
  • netifaces reads:
    • full Ethernet/IP/IPv6-Information
    • but no meaningful interface-names

Mixing both, provides everything needed.

  1. Netifaces only
  2. from netifaces import AF_INET, AF_INET6, AF_LINK
    import netifaces
    
    for i in netifaces.interfaces():
       niif=netifaces.ifaddresses(i)
       print("i",i)
       for k,v in niif.items():
         print("Key",k)
         if k==AF_LINK:
           print("LINK:",v)
         if k==AF_INET:
           print("IPv4",v)
         if k==AF_INET6:
           print("IPv6",v)
       print()
    
    >>> for i in netifaces.interfaces():
    ...    niif=netifaces.ifaddresses(i)
    ...    print("i",i)
    ...    for k,v in niif.items():
    ...      print("Key",k)
    ...      if k==AF_LINK:
    ...        print("LINK:",v)
    ...      if k==AF_INET:
    ...        print("IPv4",v)
    ...      if k==AF_INET6:
    ...        print("IPv6",v)
    ...    print()
    ...
    i {07E9D8A4-E167-4FFF-B851-61A20C49AE6E}
    Key -1000
    LINK: [{'addr': '00:00:81:00:de:11'}]
    Key 23
    IPv6 [{'addr': 'fe80::8400:abb0:2a62:a173%4', 'netmask': 'ffff:ffff:ffff:ffff::/64', 'broadcast': 'fe80::ffff:ffff:ffff:ffff%4'}]
    
    i {D30DEC05-D495-4DA1-81F1-42B07885B0EB}
    Key -1000
    LINK: [{'addr': '0a:00:27:00:00:14'}]
    Key 23
    IPv6 [{'addr': 'fe80::1e0:4a4:8afc:90f7%20', 'netmask': 'ffff:ffff:ffff:ffff::/64', 'broadcast': 'fe80::ffff:ffff:ffff:ffff%20'}]
    Key 2
    IPv4 [{'addr': '192.168.56.1', 'netmask': '255.255.255.0', 'broadcast': '192.168.56.255'}]
    
    i {402C453F-4B74-4883-9257-BD31FAB7AB57}
    Key -1000
    LINK: [{'addr': '74:70:fd:bd:10:38'}]
    Key 23
    IPv6 [{'addr': 'fe80::2599:368f:e80d:94b6%8', 'netmask': 'ffff:ffff:ffff:ffff::/64', 'broadcast': 'fe80::ffff:ffff:ffff:ffff%8'}]
    
    i {2120C2CA-E7D4-45DF-8090-A8D7F48EFF42}
    Key -1000
    LINK: [{'addr': '76:70:fd:bd:10:37'}]
    Key 23
    IPv6 [{'addr': 'fe80::34d6:9683:4af5:afad%6', 'netmask': 'ffff:ffff:ffff:ffff::/64', 'broadcast': 'fe80::ffff:ffff:ffff:ffff%6'}]
    
    i {F931F123-70A4-4CFB-BD9C-C0A509080286}
    Key -1000
    LINK: [{'addr': '74:70:fd:bd:10:37'}]
    Key 23
    IPv6 [{'addr': 'fe80::1926:3c29:1b34:e1f6%22', 'netmask': 'ffff:ffff:ffff:ffff::/64', 'broadcast': 'fe80::ffff:ffff:ffff:ffff%22'}]
    Key 2
    IPv4 [{'addr': '192.168.1.163', 'netmask': '255.255.255.0', 'broadcast': '192.168.1.255'}]
    
    i {693A5869-6A31-11E8-85D1-806E6F6E6963}
    Key -1000
    LINK: [{'addr': ''}]
    Key 23
    IPv6 [{'addr': '::1', 'netmask': 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128', 'broadcast': '::1'}]
    Key 2
    IPv4 [{'addr': '127.0.0.1', 'netmask': '255.0.0.0', 'broadcast': '127.255.255.255'}]
    
  3. Adding Scapy to get meaningful interface names
  4. from scapy.all import *
    
    for i in ifaces.data.keys():
      print(i)
      iface = ifaces.data[i]
      wname = iface.data['netid']
      addresses = netifaces.ifaddresses(i)
      af_inet = [{"addr": "0.0.0.0", "netmask": "0.0.0.0", "broadcast": "0.0.0.0"}]
      if AF_INET in addresses:
        af_inet = netifaces.ifaddresses(i)[AF_INET]
      print(wname,af_inet)
    
    >>> for i in ifaces.data.keys():
    ...   print(i)
    ...   iface = ifaces.data[i]
    ...   wname = iface.data['netid']
    ...   addresses = netifaces.ifaddresses(i)
    ...   af_inet = [{"addr": "0.0.0.0", "netmask": "0.0.0.0", "broadcast": "0.0.0.0"}]
    ...   if AF_INET in addresses:
    ...     af_inet = netifaces.ifaddresses(i)[AF_INET]
    ...   print(wname,af_inet)
    ...
    {F931F123-70A4-4CFB-BD9C-C0A509080286}
    Wi-Fi [{'addr': '192.168.1.163', 'netmask': '255.255.255.0', 'broadcast': '192.168.1.255'}]
    {D30DEC05-D495-4DA1-81F1-42B07885B0EB}
    VirtualBox Host-Only Network [{'addr': '192.168.56.1', 'netmask': '255.255.255.0', 'broadcast': '192.168.56.255'}]
    {07E9D8A4-E167-4FFF-B851-61A20C49AE6E}
    ETH_DELL [{'addr': '0.0.0.0', 'netmask': '0.0.0.0', 'broadcast': '0.0.0.0'}]
    
    

Python „netifaces“ installation: „Microsoft Visual C++ 14.0 is required“

I expected a nobrainer:

C:\RH>pip install netifaces
Collecting netifaces
  Downloading https://files.pythonhosted.org/packages/81/39/4e9a026265ba944ddf1fea176dbb29e0fe50c43717ba4fcf3646d099fe38/netifaces-0.10.7.tar.gz
Installing collected packages: netifaces
  Running setup.py install for netifaces ... error
    Complete output from command c:\users\rh\appdata\local\programs\python\python37\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\RH\\AppData\\Local\\Temp\\pip-install-wbfanly3\\netifaces\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\RONALD~1.HEI\AppData\Local\Temp\pip-record-m26yfbyt\install-record.txt --single-version-externally-managed --compile:
    running install
    running build
    running build_ext
    building 'netifaces' extension
    error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools

The suggested URL to download the missing software is wrong (HTTP 404).

  1. Go to the Microsoft-Repository Tools for Visual Studio 2017 or use the direct link to vs_buildtools.exe

    • …it’s about 1.2MB
  2. run „vs_buildtools.exe“
    • …it downloads ~ 70 MB
  3. Select „Workloads => Windows => [x] Visual C++ Build Tools“ => [Install]
    • …it downloads 1.12 GB
    • …and installs
  4. and … unlucky…

  5. reboot required

Now netifaces can get installed:

C:\RH>pip install netifaces
Collecting netifaces
  Using cached https://files.pythonhosted.org/packages/81/39/4e9a026265ba944ddf1fea176dbb29e0fe50c43717ba4fcf3646d099fe38/netifaces-0.10.7.tar.gz
Installing collected packages: netifaces
  Running setup.py install for netifaces ... done
Successfully installed netifaces-0.10.7

Python Scapy: Wait for CDP-Neighbor

After provisioning a new Cisco CSR1000V-Router this script

  • waits until the router is fully deployed
  • got it’s Management-IP-Address assigned via DHCP.

and returns this Management IP-Address.

  1. Prepare
  2. First, install „netaddr“-package.

    • needed to check, if the management-IP of the CDP-Neighbor is in the correct IP-Subnet
    C:\RH>pip install netaddr
    Collecting netaddr
      Downloading https://files.pythonhosted.org/packages/ba/97/ce14451a9fd7bdb5a397abf99b24a1a6bb7a1a440b019bebd2e9a0dbec74/netaddr-0.7.19-py2.py3-none-any.whl (1.6MB)
        100% |████████████████████████████████| 1.6MB 4.0MB/s
    Installing collected packages: netaddr
    Successfully installed netaddr-0.7.19
    
  3. the „wait-for-CDP“-Script
  4. Obviously far to much hard-coded stuff, just as an example 😉 waiting for a CDP-Neighbor to appear with the following properties:

    • hostname „CSR-A“
    • an IP-Address within the network „192.168.56.0 /24“
    • at the interface

    • VirtualBox Host-Only-Network
    #! /usr/bin/env python
    
    from scapy.all import *
    load_contrib("cdp")
    
    from netaddr import IPNetwork, IPAddress
    
    # run it for max. 99 Packets
    ip = "0.0.0.0"
    wait_for_hostname = "CSR-A"
    wait_for_host_in_network = "192.168.56.0/24"
    
    interface="VirtualBox Host-Only Ethernet Adapter"
    capturefilter="ether dst 01:00:0c:cc:cc:cc"
    
    while not(IPAddress(ip) in IPNetwork(wait_for_host_in_network)):
      p=sniff(iface=interface, count=1, filter=capturefilter)
      pkt=p[0]
      #print("Packet received",pkt.show())
    
      #is this a CDP-Packet containing a hostname?
      if (CDPMsgDeviceID in pkt):
        #is this the CDP-Neighbor we're looking for?
        device=pkt["CDPMsgDeviceID"].val.decode()
        hostname=device.split(".")[0]
        #print("Hostname:",hostname)
    
        if (hostname == wait_for_hostname):
          #is this a CDP-Packet containing a management-IP-Address?
          if (CDPAddrRecordIPv4 in pkt):
            ip=pkt["CDPAddrRecordIPv4"].addr
            #print("IP-Address found:",ip)
    
    #return the IP-Address to the calling application or the CLI
    print(ip)
    
  5. Provision a new CSR1000V Router named „CSR-A“
  6. C:\RH>CSR1000v-Virtual-Box.cmd
    Enter CSR1000v Hostname:CSR-A
    Virtual machine 'CSR-A' is created and registered.
    UUID: 8a9c969e-3895-4a7c-9cbc-5f5551bf1b7b
    Settings file: 'c:\RH\LAB\VM\CSR-A\CSR-A.vbox'
    Creating ISO image at c:\RH\LAB\VM\CSR-A\config.iso, 1 Files, Size: 8,00 KB
    100%
    0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
    Medium created. UUID: 55ea8df5-7e3c-4485-8e08-9302cb61a09d
    Waiting for VM "CSR-A" to power on...
    VM "CSR-A" has been successfully started.
    
  7. Run the „wait-for-CDP-Neighbor“-Script
  8. In a second CMD-Box, and… Be patient, of course.

    C:\RH>python wait-for-cdpneighbor.py
    192.168.56.101
    
  9. Or store the returned IP-Address in an Shell-Variable „ROUTER-IP“/li>
    C:\RH>for /f %I in ('python wait-for-cdpneighbor.py 2^> nul') do @(set ROUTER-IP=%I)
    
  10. and pass it to putty – using public-key authentication
  11. The Public-Key for user „labuser“ is part of my baseline-config used to provision the virtual-router.

    C:\RH>putty -ssh -i C:\RH\work\putty-rsa-key\labuser.ppk labuser@%ROUTER-IP%
    

    Works, this is a nice preparation for an automated virtual ansible-lab, too!

Python Scapy: CDP-Monitor

Watch and decode Cisco Discovery Protocol Packetes.

  1. CDP Monitor-Script
  2. Inspired by the Scapy ARP-Monitor i created an CDP-Monitor displaying hostname and an optional Management-IP-Address.

    #! /usr/bin/env python
    from scapy.all import *
    load_contrib("cdp")
    
    def cdp_monitor_callback(pkt):
      ip = "0.0.0.0"
      if (CDPMsgDeviceID in pkt):
        device=pkt["CDPMsgDeviceID"].val.decode()
        hostname=device.split(".")[0]
        if (CDPAddrRecordIPv4 in pkt):
          ip=pkt["CDPAddrRecordIPv4"].addr
        return "Device: {0} IP: {1}".format(hostname,ip)
    
    interface="VirtualBox Host-Only Ethernet Adapter"
    capturefilter="ether dst 01:00:0c:cc:cc:cc"
    
    # run it for max. 99 Packets
    p=sniff(prn=cdp_monitor_callback, iface=interface, count=99, filter=capturefilter, store=0)
    
  3. Real-Life Example
    • Run this script:
    • C:\RH>python
      Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
      Type "help", "copyright", "credits" or "license" for more information.
      >>> #! /usr/bin/env python
      ... from scapy.all import *
      >>> load_contrib("cdp")
      >>>
      >>> def cdp_monitor_callback(pkt):
      ...   ip = "0.0.0.0"
      ...   if (CDPMsgDeviceID in pkt):
      ...     device=pkt["CDPMsgDeviceID"].val.decode()
      ...     hostname=device.split(".")[0]
      ...     if (CDPAddrRecordIPv4 in pkt):
      ...       ip=pkt["CDPAddrRecordIPv4"].addr
      ...     return "Device: {0} IP: {1}".format(hostname,ip)
      ...
      >>> interface="VirtualBox Host-Only Ethernet Adapter"
      >>> capturefilter="ether dst 01:00:0c:cc:cc:cc"
      >>>
      >>> # run it for max. 99 Packets
      ... p=sniff(prn=cdp_monitor_callback, iface=interface, count=99, filter=capturefilter, store=0)
      
    • Open another CMD-Window to spin up a new CSR1000V-Router:
    • C:\RH\work\entwicklung\csr1000v-provision-in-virtualbox>CSR1000v-Virtual-Box.cmd
      Enter CSR1000v Hostname:CSR-CDPTEST-A
      Virtual machine 'CSR-CDPTEST-A' is created and registered.
      UUID: eaa931bd-9db4-4a78-b263-754d4bb300a0
      Settings file: 'c:\RH\LAB\VM\CSR-CDPTEST-A\CSR-CDPTEST-A.vbox'
      Creating ISO image at c:\RH\LAB\VM\CSR-CDPTEST-A\config.iso, 1 Files, Size: 8,00 KB
      100%
      0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
      Medium created. UUID: 3019216e-2e61-435a-95f2-3d26312c3ed9
      Waiting for VM "CSR-CDPTEST-A" to power on...
      VM "CSR-CDPTEST-A" has been successfully started.
      
    • Go back to the „python“-Screen and wait:
    • >>> # run it for max. 99 Packets
      ... p=sniff(prn=cdp_monitor_callback, iface=interface, count=99, filter=capturefilter, store=0)
      Device: CSR-CDPTEST-A IP: 0.0.0.0
      Device: CSR-CDPTEST-A IP: 0.0.0.0
      Device: CSR-CDPTEST-A IP: 0.0.0.0
      Device: CSR-CDPTEST-A IP: 0.0.0.0
      Device: CSR-CDPTEST-A IP: 0.0.0.0
      Device: CSR-CDPTEST-A IP: 10.0.2.15
      Device: CSR-CDPTEST-A IP: 10.0.2.15
      Device: CSR-CDPTEST-A IP: 10.0.2.15
      

      It works, the IOS-XE CSR1000V-Router is installed and it got it’s baseline-config applied:

      • Hostname
      • Interface set to „ip address dhcp“
      • CDP enabled

      takes some time, but these first CDP-Packets captured were not sent in 60s interval, so don’t be scared 😉

Python Scapy: Capturing „Cisco Discovery Protocol (CDP)“

It’s hard to believe, how easy it is to capture (and to craft) LAN-Data using Python Scapy.

I need to capture CDP-Packets and to extract information like the hostname of the sender and it’s IP-Address.

As an modification of the „ARP-Monitor“-example taken from the manual Using scapy in your tools.

  1. Scapy Installation
  2. nothing special: pip install

    C:\RH>pip install scapy
    Collecting scapy
      Downloading https://files.pythonhosted.org/packages/68/01/b9943984447e7ea6f8948e90c1729b78161c2bb3eef908430638ec3f7296/scapy-2.4.0.tar.gz (3.1MB)
        100% |████████████████████████████████| 3.1MB 420kB/s
      In the tar file C:\Users\RONALD~1.HEI\AppData\Local\Temp\pip-unpack-4jm9kde1\scapy-2.4.0.tar.gz the member scapy-2.4.0/README is invalid: unable to resolve link inside archive
    Installing collected packages: scapy
      Running setup.py install for scapy ... done
    Successfully installed scapy-2.4.0
    
  3. Python: Install Scapy
  4. C:\RH>python
    Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    
    >>> from scapy.all import *
    
  5. Example: List all Interfaces of my Laptop
  6. >>> ifaces
    INDEX  IFACE                                     IP            MAC
    20     VirtualBox Host-Only Ethernet Adapter     192.168.56.1  0A:00:27:00:00:14
    22     Intel(R) Dual Band Wireless-AC 8265       172.20.10.2   IntelCor:BD:10:37
    4      Intel(R) Ethernet Connection (4) I219-LM  47.11.17.10   BayNetwo:00:DE:11
    
    >>> for i in ifaces.data.keys():
    ...     iface = ifaces.data[i]
    ...     name = str(iface.name)
    ...     wname = iface.data['netid']
    ...     mac = str(iface.mac)
    ...     ip  = str(iface.ip)
    ...     print("DESCR:{0}, NAME:{1}, MAC:{2}, IP:{3}".format(wname,name,mac,ip))
    ...
    DESCR:Wi-Fi, NAME:Intel(R) Dual Band Wireless-AC 8265, MAC:74:70:FD:BD:10:37, IP:172.20.10.2
    DESCR:VirtualBox Host-Only Network, NAME:VirtualBox Host-Only Ethernet Adapter, MAC:0A:00:27:00:00:14, IP:192.168.56.1
    DESCR:ETH_DELL, NAME:Intel(R) Ethernet Connection (4) I219-LM, MAC:00:00:81:00:DE:11, IP:47.11.17.10
    
  7. Capture 10 Packets on a specific interface
  8. The "NAME" is needed as interface-handle
    >>> interface="VirtualBox Host-Only Ethernet Adapter"
    
    >>> p=sniff(iface=interface, count=10)
    >>> p.display()
    0000 Ether / IP / UDP 192.168.56.1:17500 > 255.255.255.255:17500 / Raw
    0001 Ether / IP / UDP 192.168.56.1:17500 > 255.255.255.255:17500 / Raw
    0002 Ether / IP / UDP 192.168.56.1:17500 > 192.168.56.255:17500 / Raw
    0003 Ether / IP / UDP 192.168.56.1:17500 > 255.255.255.255:17500 / Raw
    0004 Ether / IP / UDP 192.168.56.1:17500 > 255.255.255.255:17500 / Raw
    0005 Ether / IP / UDP 192.168.56.100:bootps > 255.255.255.255:bootpc / BOOTP / DHCP
    0006 Ether / IP / UDP 192.168.56.102:50472 > 255.255.255.255:10067 / Raw
    0007 Ether / IP / UDP 192.168.56.103:49580 > 255.255.255.255:10067 / Raw
    0008 Ether / IP / UDP 192.168.56.1:17500 > 255.255.255.255:17500 / Raw
    0009 Ether / IP / UDP 192.168.56.1:17500 > 255.255.255.255:17500 / Raw
    
  9. Capture CDP-Packets
  10. Capture CDP
    
    >>> p=sniff(iface=interface, count=2, filter="ether dst 01:00:0c:cc:cc:cc")
    >>> p
    <Sniffed: TCP:0 UDP:0 ICMP:0 Other:2>
    >>> p.display()
    0000 802.3 08:00:27:c9:d5:7e > 01:00:0c:cc:cc:cc / LLC / SNAP / Raw
    0001 802.3 08:00:27:c9:d5:7e > 01:00:0c:cc:cc:cc / LLC / SNAP / Raw
    
  11. Decode CDP (with inactive dissector)
  12. >>> p[0].display()
    ###[ 802.3 ]###
      dst       = 01:00:0c:cc:cc:cc
      src       = 08:00:27:c9:d5:7e
      len       = 386
    ###[ LLC ]###
         dsap      = 0xaa
         ssap      = 0xaa
         ctrl      = 3
    ###[ SNAP ]###
            OUI       = 0xc
            code      = 0x2000
    ###[ Raw ]###
               load      = '\x02\xb4\x91\x18\x00\x01\x00\x13CSR-A.lab.local\x00\x05\x01\x05Cisco IOS Software [Fuji], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.9.1, RELEASE SOFTWARE (fc2)\nTechnical Support: http://www.cisco.com/techsupport\nCopyright (c) 1986-2018 by Cisco Systems, Inc.\nCompiled Tue 17-Jul-18 16:57 by mcpre\x00\x06\x00\x12cisco CSR1000V\x00\x02\x00\x11\x00\x00\x00\x01\x01\x01\xcc\x00\x04\xc0\xa88e\x00\x03\x00\x14GigabitEthernet2\x00\x04\x00\x08\x00\x00\x00!\x00\x07\x00\t\n\x00\x02\x00\x18\x00\x0b\x00\x05\x01\x00\x16\x00\x11\x00\x00\x00\x01\x01\x01\xcc\x00\x04\xc0\xa88e'
    
  13. Activate the CDP-Parser
  14. >>> list_contrib()
    avs                 : AVS WLAN Monitor Header                  status=loads
    bgp                 : BGP v0.1                                 status=loads
    carp                : CARP                                     status=loads
    cdp                 : Cisco Discovery Protocol                 status=loads
    chdlc               : Cisco HDLC and SLARP                     status=loads
    coap                : Constrained Application Protocol (CoAP)  status=loads
    diameter            : Diameter                                 status=loads
    dtp                 : DTP                                      status=loads
    eigrp               : EIGRP                                    status=loads
    etherip             : EtherIP                                  status=loads
    gsm_um              : PPI                                      status=loads
    gtp                 : GTP                                      status=loads
    gtp_v2              : GTPv2                                    status=loads
    homeplugav          : HomePlugAV Layer                         status=loads
    http2               : HTTP/2 (RFC 7540, RFC 7541)              status=loads
    icmp_extensions     : ICMP Extensions                          status=loads
    igmp                : IGMP/IGMPv2                              status=loads
    igmpv3              : IGMPv3                                   status=loads
    ikev2               : IKEv2                                    status=loads
    isis                : ISIS                                     status=loads
    ldp                 : Label Distribution Protocol (LDP)        status=loads
    lldp                : LLDP                                     status=loads
    macsec              : -                                        status=?
    modbus              : ModBus Protocol                          status=loads
    mpls                : MPLS                                     status=loads
    mqtt                : -                                        status=?
    nsh                 : NSH Protocol                             status=loads
    openflow            : Openflow v1.0                            status=loads
    openflow3           : Openflow v1.3                            status=loads
    ospf                : OSPF                                     status=loads
    pnio                : ProfinetIO base layer                    status=loads
    pnio_rtc            : ProfinetIO Real-Time Cyclic (RTC)        status=loads
    ppi                 : PPI                                      status=loads
    ppi_cace            : PPI CACE                                 status=loads
    ppi_geotag          : PPI GEOLOCATION                          status=loads
    ripng               : RIPng                                    status=loads
    rsvp                : RSVP                                     status=loads
    sebek               : Sebek                                    status=loads
    send                : Secure Neighbor Discovery (SEND) (ICMPv6) status=loads
    skinny              : Skinny Call Control Protocol (SCCP)      status=loads
    spbm                : SBPM                                     status=loads
    tacacs              : TACACS+ Protocol                         status=loads
    tzsp                : TZSP                                     status=loads
    ubberlogger         : Ubberlogger dissectors                   status=loads
    vqp                 : VLAN Query Protocol                      status=loads
    vtp                 : VLAN Trunking Protocol (VTP)             status=loads
    wpa_eapol           : WPA EAPOL dissector                      status=loads
    
    >>> load_contrib("cdp")
    
  15. Capture again and display CDP-Information as cleartext
  16. >>> load_contrib("cdp")
    
    >>> p=sniff(iface=interface, count=1, filter=capturefilter)
    >>>
    >>>
    >>> p[0].show()
    ###[ 802.3 ]###
      dst       = 01:00:0c:cc:cc:cc
      src       = 08:00:27:c9:d5:7e
      len       = 386
    ###[ LLC ]###
         dsap      = 0xaa
         ssap      = 0xaa
         ctrl      = 3
    ###[ SNAP ]###
            OUI       = 0xc
            code      = 0x2000
    ###[ Cisco Discovery Protocol version 2 ]###
               vers      = 2
               ttl       = 180
               cksum     = 0x9118
               \msg       \
                |###[ Device ID ]###
                |  type      = Device ID
                |  len       = 19
                |  val       = 'CSR-A.lab.local'
                |###[ Software Version ]###
                |  type      = Software Version
                |  len       = 261
                |  val       = 'Cisco IOS Software [Fuji], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.9.1, RELEASE SOFTWARE (fc2)\nTechnical Support: http://www.cisco.com/techsupport\nCopyright (c) 1986-2018 by Cisco Systems, Inc.\nCompiled Tue 17-Jul-18 16:57 by mcpre'
                |###[ Platform ]###
                |  type      = Platform
                |  len       = 18
                |  val       = 'cisco CSR1000V'
                |###[ Addresses ]###
                |  type      = Addresses
                |  len       = 17
                |  naddr     = 1
                |  \addr      \
                |   |###[ CDP Address IPv4 ]###
                |   |  ptype     = NLPID
                |   |  plen      = 1
                |   |  proto     = '\xcc'
                |   |  addrlen   = 4
                |   |  addr      = 192.168.56.101
                |###[ Port ID ]###
                |  type      = Port ID
                |  len       = 20
                |  iface     = 'GigabitEthernet2'
                |###[ Capabilities ]###
                |  type      = Capabilities
                |  len       = 8
                |  cap       = Router+IGMPCapable
                |###[ IP Prefix ]###
                |  type      = IP Prefix
                |  len       = 9
                |  defaultgw = 10.0.2.0
                |###[ CDP Generic Message ]###
                |  type      = 0x1800
                |  len       = 2816
                |  val       = '\x05\x01\x00\x16\x00\x11\x00\x00\x00\x01\x01\x01\xcc\x00\x04\xc0\xa88e'
    
  17. Decode CDP-Hostname
  18. >>> device=p[0]["CDPMsgDeviceID"].val.decode()
    >>> device
    'CSR-A.lab.local'
    >>> hostname=device.split(".")[0]
    >>> hostname
    'CSR-A'
    
  19. Decode CDP-Management-IP-Address
  20. >>> ip=p[0]["CDPAddrRecordIPv4"]
    >>> ip.addr
    '192.168.56.101'
    

Windows Command Shell: Store the output of another command in a variable.

How often had i to look up this in the web, always wondering about myself still using the Windows-CMD-shell… Should move on to powershell…

store the output of another command in a variable

  • Example: the „date“-command
  • c:\RH\>date /T
    30.10.2018
    
  • Copy the date into the variable „TTT“
  • c:\RH\>for /f %D in ('date /T 2^> nul') do @(set TTT=%D)
    
    c:\RH\>echo %TTT%
    30.10.2018
    

Not elegant, not intuitive, not self-explanatory: This Shell Scripting language seems not to be made for daily usage 😉

Scripted provisioning of a Cisco CSR1000V as VirtualBox-Guest: Slipstream initial startup-config

To enable immediate remote-access to brandnew deployed virtual Cisco CSR1000V-Routers by scripts, ansible etc. it’s necessary to predeploy the startup-config at least with public-rsa-keys etc.

  1. Prepare
  2. Download and install the nice tool http://CDBurnerXP. This will install a companion cli-tool cdbxpcmd.exe along with the GUI-Version.

    It’ll be used to prepare an ISO-„CDROM“ containing the prepared „startup-config“-file.

  3. Prepare
  4. Prepare an IOS-XE Configuration file…

    !
    hostname HOSTNAME
    !
    ...
    !
    !
    platform console serial
    !
    crypto key generate rsa modulus 2048 label RSA_SSH
    !
    !
    username labuser privilege 15
    !
    ip ssh pubkey-chain
    !
    username labuser
      key-string    
      ...
    exit
    exit
    !
    exit
    !
    ...
    !
    ip ssh rsa keypair-name RSA_SSH
    !
    ip ssh server algorithm authentication publickey
    !
    ...
    !
    line vty 0 15
      login local
      transport input ssh
      access-class ACL_NMM in vrf-also
    !
    end
    
  5. Modify the existing script
  6. These commands create the ISO-File in the %LOC%-Path.

    set VM=CSR1000vX
    
    ...
    
    : Create ISO containing slipstreamed config-file
    : use UNXTOOLS "sed" to customize the "hostname"-Command
    :
    set CFGISO=%LOC%\config.iso
    set CFGSRC=C:\RH\LAB\VM\iosxe_config.txt
    set CFGTXT=%LOC%\iosxe_config.txt
    cat %CFGSRC% | sed "s/HOSTNAME/%VM%/g" > %CFGTXT%
    "%ProgramFiles(x86)%"\CDBurnerXP\cdbxpcmd.exe --burn-data -file:%CFGTXT% -iso:%CFGISO% -format:iso
    
  7. Mount this ISO to the VM
  8. The contained config-file will get automatically applied when the router boots the first time.

    VBoxManage storageattach %VM% --storagectl IDE-CTL --port 1 --device 1 --type dvddrive --medium %CFGISO%
    
  9. Run the VM
    • the config-file gets applied
  10. access the router
  11. This depends of the configuration-file, of course.

Scripted provisioning of a Cisco CSR1000V as VirtualBox-Guest

In a lab environment it might be handy to quickly rollout new (virtual) routers without much manual intervention. The following script creates a VirtualBox-VM and boots it up.

  1. Prepare
  2. Install VirtualBox and have a CSR1000V-ISO-File ready.

    set VM=CSR1000V
    set BASE=c:\RH\LAB\VM
    
    set ISO=C:\Downloads\csr1000v-universalk9.16.09.01.iso
    
    : Create VM
    VBoxManage createvm --name %VM% --ostype "Linux26_64" --basefolder %BASE% --register
    
    !:now the Path in the Filesystem to ...LOC... exists
    set LOC=%BASE%\%VM%
    
    : Customize VM
    VBoxManage modifyvm %VM% --memory 4096
    VBoxManage modifyvm %VM% --vram 16
    VBoxManage modifyvm %VM% --pae on --paravirtprovider default --hwvirtex on --nestedpaging on
    
    : Storage
    VBoxManage createhd --filename %LOC%\%VM%.vdi --size 8192
    VBoxManage storagectl %VM% --name "IDE-CTL" --add ide --portcount 2 --bootable on
    VBoxManage storageattach %VM% --storagectl IDE-CTL --port 0 --device 0 --type hdd --medium %LOC%\%VM%.vdi
    VBoxManage storageattach %VM% --storagectl IDE-CTL --port 1 --device 0 --type dvddrive --medium %ISO%
    
    VBoxManage modifyvm %VM% --boot1=dvd --boot2=disk --boot3=none --boot4=none
    
    : Serial-Interfaces via "Pipe"
    VBoxManage modifyvm %VM% --uartmode1 server \\.\pipe\%VM%
    VBoxManage modifyvm %VM% --uart1 0x3f8 4
    VBoxManage modifyvm %VM% --uartmode2 server \\.\pipe\%VM%_diag
    VBoxManage modifyvm %VM% --uart2 0x2f8 4
    
    : Audio
    VBoxManage modifyvm %VM% --audio none
    
    : NICs
    VBoxManage modifyvm %VM% --nic1 nat --nic2 hostonly --nic3 hostonly --nic4 hostonly
    VBoxManage modifyvm %VM% --nictype1 virtio --nictype2 virtio --nictype3 virtio --nictype4 virtio
    VBoxManage modifyvm %VM% --nicpromisc1 allow-all --nicpromisc2 allow-all --nicpromisc3 allow-all --nicpromisc4 allow-all
    VBoxManage modifyvm %VM% --hostonlyadapter2 "VirtualBox Host-Only Ethernet Adapter"
    VBoxManage modifyvm %VM% --hostonlyadapter3 "VirtualBox Host-Only Ethernet Adapter"
    VBoxManage modifyvm %VM% --hostonlyadapter4 "VirtualBox Host-Only Ethernet Adapter"
    
    : Set the VM-Logo for the VirtualBox-Inventory
    VBoxManage modifyvm %VM% --iconfile C:\RH\LAB\72px-Cisco_logo.svg.png
    
    : Boot the VM, it'l reboot once to apply the running-config
    VBoxManage startvm %VM%
    
  3. Execute
  4. The Inventory populates:

  5. Use it
  6. conf t
      platform console serial
    end
    

    After another reboot the serial console can be accessed by a windows pipe:

    The pipe provides access to the serial-console:

Cisco IOS – Public-Key User-Authentication

It’s a two step process to get rid of insecure username/password-authentication.

  1. Generate a RSA keypair at your SSH-client
  2. btw. Cisco-IOS doesn’t support DSA-keys

  3. Configure your network device(s) to assign the (public-)key of this keypair to an user-account

This user-account could get privileges from a Radius/TACACS+-Server which could provide access-logs, too.

  1. Generate RSA-Key: Windows as SSH-Client
  2. I prefer Putty, usually in form of „mRemoteNG“, so i use PuttyGen to generate the RSA keypair.

    • Windows.Start => PuttyGen
    • (x) RSA, 4096-bits are supported, use it
    • [Generate]
    • move the mouse to improve the randomgenerator
    • change the „comment“ – for example replace it by an username
    • add a passphrase – using this key-pair is possible only for people knowing this passphrase
    • Save both parts of the RSA keypair:
      • [Save public key] => Filename for example „labuser.pub“
      • [Save private key] => Filename for example „labuser.ppk“
    • Verify
    • C:>dir labuser*.* -l
      -rw-rw-rw-   1 user     group        2710 Oct 17 18:26 labuser.ppk
      -rw-rw-rw-   1 user     group         820 Oct 17 18:26 labuser.pub
      
    • Since the contained keys are BASE64-Encoded (The Secure Shell (SSH) Public Key File Format) you could extract them using grep.
    • C:>cat labuser.pub
      ---- BEGIN SSH2 PUBLIC KEY ----
      Comment: "labuser"
      AAAAB3NzaC1yc2EAAAABJQAAAgEAg+0v9spZ0ZaBmgK3eVWJmY1Q4bNYcuY/uZDn
      c0JFPXgn9dA5r44GksqIEpYjkbMZf61Nkwazz4Cfxw4byS/HeajYP8Rs/eWXV6dh
      k829tqvqSLN6TwH+v49MllGpiHbiVGyoRvzfPgUVddN1j8cMEIJHgVJk4AS4fJmx
      Mp+2wMFWGldJ5xlUaOXO+XaOaTlAFYimgdYNbO7x4+vMRtrqp3ORJJZ5Tdf0JuFp
      cUHRlV46e2FL1FZ8p2PDLVUiAlg8o8yxI8D52r0A5VQToKz3wKUchTWIWqRmIfOR
      fS5jJz8+yTb/swkFs4FzAEpxD8CgvArz7ewTkna0zm8/wbysZCH1lKyce7AmZCp9
      lm1Nsythl+6ztB9M01AbzBo2ElVo3GZHEr3AclsON8aCKgf8hVaZww5BqN1YHvUj
      dKH0Mb8i0zLs+XFSgV7rYXg1EcHyBqsRFAi5OdkuGwd5D2NfWkcwk2XBsi6qG8bP
      951MlHi0SuiMTSTmskdf1OyzzIFaPYjaW9VQe36tg07MsBP48KOPEB4803k35gWx
      Sw2nxAO4O9KisYNCfw0SHna9RiAWRsyykLUTe6Z39vzppTEiC+j2f6IQs9Celk4S
      s9r8IIoI0yswtvc/DsJBLd8y0CmNwyZof9L5MSY1RlcBiCykUPh1Z+UFLEYrFBa1
      qQCAwU8=
      ---- END SSH2 PUBLIC KEY ----
      
    • THIS output could be directly used within Cisco-IOS command syntax:
    • C:>egrep "^[a-zA-Z0-9+\/=]+$" labuser.pub
      AAAAB3NzaC1yc2EAAAABJQAAAgEAg+0v9spZ0ZaBmgK3eVWJmY1Q4bNYcuY/uZDn
      c0JFPXgn9dA5r44GksqIEpYjkbMZf61Nkwazz4Cfxw4byS/HeajYP8Rs/eWXV6dh
      k829tqvqSLN6TwH+v49MllGpiHbiVGyoRvzfPgUVddN1j8cMEIJHgVJk4AS4fJmx
      Mp+2wMFWGldJ5xlUaOXO+XaOaTlAFYimgdYNbO7x4+vMRtrqp3ORJJZ5Tdf0JuFp
      cUHRlV46e2FL1FZ8p2PDLVUiAlg8o8yxI8D52r0A5VQToKz3wKUchTWIWqRmIfOR
      fS5jJz8+yTb/swkFs4FzAEpxD8CgvArz7ewTkna0zm8/wbysZCH1lKyce7AmZCp9
      lm1Nsythl+6ztB9M01AbzBo2ElVo3GZHEr3AclsON8aCKgf8hVaZww5BqN1YHvUj
      dKH0Mb8i0zLs+XFSgV7rYXg1EcHyBqsRFAi5OdkuGwd5D2NfWkcwk2XBsi6qG8bP
      951MlHi0SuiMTSTmskdf1OyzzIFaPYjaW9VQe36tg07MsBP48KOPEB4803k35gWx
      Sw2nxAO4O9KisYNCfw0SHna9RiAWRsyykLUTe6Z39vzppTEiC+j2f6IQs9Celk4S
      s9r8IIoI0yswtvc/DsJBLd8y0CmNwyZof9L5MSY1RlcBiCykUPh1Z+UFLEYrFBa1
      qQCAwU8=
      
  3. Generate RSA-Key: Linux as SSH-Client
    • there might already exist a rsa-key in the „.ssh“-path of your home-directory
    • $ cd ~/.ssh/
      $ ls -l
      total 20
      -rw------- 1 administrator administrator 1675 Aug 28 09:43 id_rsa
      -rw-r--r-- 1 administrator administrator  405 Aug 28 09:43 id_rsa.pub
      -rw-r--r-- 1 administrator administrator  222 Aug 28 11:07 known_hosts
      
      $ cat id_rsa.pub
      ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCohMsS3gJ/OcF4Hg43mKeVHKWl2lECCn0iZQu9QSrUjAb4PVHWXIbj11yy5Jh/ygMys0n9IED6357fkRmq8Cc8ujpU0sCen7kBFUt3UqbLg1PLT9wMmJAEv4dcxbX9WRvwYXjLd8+EgDYDmrj7vTB3xIvw1I2WWuUK2jPWbVI57vbyGtw224Qb9Qk0KQfyGiTvErZnddDg65/rn9Pyt7FQlzCwUPH0nyJVoFhiYYJYJszTKc8BTFB6VdIbALHc4atFmjYt7YDUvEvaZqOL+zwQtr7FmXsZ5oaRGV6ZChuBPTpNEL41w/Il1mSJicRykpD90O2AxlUFebQfABTWadnr administrator@lx-ubuntu
      

      The RFC states that the key should get split into multiple lines containing max. 72 characters.

    • use
      • „cut“ to extract the encoded-key
      • „fold“ to split the key into multiple lines
    • $ cut -d " " -f 2 id_rsa.pub
      AAAAB3NzaC1yc2EAAAADAQABAAABAQCohMsS3gJ/OcF4Hg43mKeVHKWl2lECCn0iZQu9QSrUjAb4PVHWXIbj11yy5Jh/ygMys0n9IED6357fkRmq8Cc8ujpU0sCen7kBFUt3UqbLg1PLT9wMmJAEv4dcxbX9WRvwYXjLd8+EgDYDmrj7vTB3xIvw1I2WWuUK2jPWbVI57vbyGtw224Qb9Qk0KQfyGiTvErZnddDg65/rn9Pyt7FQlzCwUPH0nyJVoFhiYYJYJszTKc8BTFB6VdIbALHc4atFmjYt7YDUvEvaZqOL+zwQtr7FmXsZ5oaRGV6ZChuBPTpNEL41w/Il1mSJicRykpD90O2AxlUFebQfABTWadnr
      
      $ cut -d " " -f 2 id_rsa.pub | fold -b -w 72
      AAAAB3NzaC1yc2EAAAADAQABAAABAQCohMsS3gJ/OcF4Hg43mKeVHKWl2lECCn0iZQu9QSrU
      jAb4PVHWXIbj11yy5Jh/ygMys0n9IED6357fkRmq8Cc8ujpU0sCen7kBFUt3UqbLg1PLT9wM
      mJAEv4dcxbX9WRvwYXjLd8+EgDYDmrj7vTB3xIvw1I2WWuUK2jPWbVI57vbyGtw224Qb9Qk0
      KQfyGiTvErZnddDg65/rn9Pyt7FQlzCwUPH0nyJVoFhiYYJYJszTKc8BTFB6VdIbALHc4atF
      mjYt7YDUvEvaZqOL+zwQtr7FmXsZ5oaRGV6ZChuBPTpNEL41w/Il1mSJicRykpD90O2AxlUF
      ebQfABTWadnr
      
    • otherwise generate a new rsa key-pair („newid_rsa“)
    • $ ssh-keygen -t rsa -b 4096
      Generating public/private rsa key pair.
      Enter file in which to save the key (/home/administrator/.ssh/id_rsa): newid_rsa
      Enter passphrase (empty for no passphrase): *****
      Enter same passphrase again: *****
      Your identification has been saved in newid_rsa.
      Your public key has been saved in newid_rsa.pub.
      The key fingerprint is:
      SHA256:4g/JkvpFQmlTaOE2VQAZ9IHfz/+6NJiI8W/WVt9TJGA administrator@lx-ubuntu
      The key's randomart image is:
      +---[RSA 4096]----+
      |   .=B=o.        |
      |   .== .    E    |
      |   .O...   . .   |
      |   + o. .     . .|
      |    . + So     o |
      |     * * .oo  . .|
      |    o B o ooo. .o|
      |   . o o .o.+. .o|
      |  ...   .o..o+. .|
      +----[SHA256]-----+
      
      $ ls -l
      total 36
      ...
      -rw------- 1 administrator administrator 3326 Oct 18 07:19 newid_rsa
      -rw-r--r-- 1 administrator administrator  749 Oct 18 07:19 newid_rsa.pub
      
  4. IOS-Router: Add those public-keys to your IOS-Config
    • i’ll use both clients (linux & windows) with the same cisco-user-account „labuser“
    • conf t
      ip ssh pubkey-chain
      username labuser
        key-string
      AAAAB3NzaC1yc2EAAAABJQAAAgEAg+0v9spZ0ZaBmgK3eVWJmY1Q4bNYcuY/uZDn
      c0JFPXgn9dA5r44GksqIEpYjkbMZf61Nkwazz4Cfxw4byS/HeajYP8Rs/eWXV6dh
      k829tqvqSLN6TwH+v49MllGpiHbiVGyoRvzfPgUVddN1j8cMEIJHgVJk4AS4fJmx
      Mp+2wMFWGldJ5xlUaOXO+XaOaTlAFYimgdYNbO7x4+vMRtrqp3ORJJZ5Tdf0JuFp
      cUHRlV46e2FL1FZ8p2PDLVUiAlg8o8yxI8D52r0A5VQToKz3wKUchTWIWqRmIfOR
      fS5jJz8+yTb/swkFs4FzAEpxD8CgvArz7ewTkna0zm8/wbysZCH1lKyce7AmZCp9
      lm1Nsythl+6ztB9M01AbzBo2ElVo3GZHEr3AclsON8aCKgf8hVaZww5BqN1YHvUj
      dKH0Mb8i0zLs+XFSgV7rYXg1EcHyBqsRFAi5OdkuGwd5D2NfWkcwk2XBsi6qG8bP
      951MlHi0SuiMTSTmskdf1OyzzIFaPYjaW9VQe36tg07MsBP48KOPEB4803k35gWx
      Sw2nxAO4O9KisYNCfw0SHna9RiAWRsyykLUTe6Z39vzppTEiC+j2f6IQs9Celk4S
      s9r8IIoI0yswtvc/DsJBLd8y0CmNwyZof9L5MSY1RlcBiCykUPh1Z+UFLEYrFBa1
      qQCAwU8=
      exit
      username labuser
        key-string    
      AAAAB3NzaC1yc2EAAAADAQABAAABAQCohMsS3gJ/OcF4Hg43mKeVHKWl2lECCn0iZQu9QSrU
      jAb4PVHWXIbj11yy5Jh/ygMys0n9IED6357fkRmq8Cc8ujpU0sCen7kBFUt3UqbLg1PLT9wM
      mJAEv4dcxbX9WRvwYXjLd8+EgDYDmrj7vTB3xIvw1I2WWuUK2jPWbVI57vbyGtw224Qb9Qk0
      KQfyGiTvErZnddDg65/rn9Pyt7FQlzCwUPH0nyJVoFhiYYJYJszTKc8BTFB6VdIbALHc4atF
      mjYt7YDUvEvaZqOL+zwQtr7FmXsZ5oaRGV6ZChuBPTpNEL41w/Il1mSJicRykpD90O2AxlUF
      ebQfABTWadnr
      exit
      
      exit
      exit
      end
      
    • Now two RSA-keys are valid to authenticate the user „labuser“
      • The Router stores only the key-hashes:
      VBOX-CSR-1#show run | section key-chain
      ip ssh pubkey-chain
        username labuser
         key-hash ssh-rsa CE7178C1D6D025F7EA5345CCBA22ED54
         key-hash ssh-rsa ABBF42AB330CA79B235FB369FCC4D53E
      
    • btw. look (above) – puttygen displayed the hash
    • ssh-rsa 4096 ce:71:78:c1:d6:d0:25:f7:ea:53:45:cc:ba:22:ed:54
      

      so you could save time to just configure the hash.

  5. Prove SSH-Client-access: Linux
    • Who am i?
    • $ who
      administrator pts/0        Oct 18 17:37 (192.168.56.1)
      

      Linux re-uses the name of the current linux-user to login into the ssh-device unless a user is specified

      $ ssh 192.168.56.102
      Password:
      

      The IOS-Router prompts for a password for users who have no known-public-key in the running-config – and there is no public-key for a user named „administrator“.

      • This is the default-behaviour:
      (config)# ip ssh server algorithm authentication publickey keyboard password
      
      • Change this undesired behaviour (disable „keyboard“ and „password“):
      conf t
        ip ssh server algorithm authentication publickey
      end
      
        Now the router blocks the access since the publickey of „administrator“ is not known.
      $ ssh 192.168.56.102
      administrator@192.168.56.102: Permission denied (publickey).
      
    • Let the linux-user „administrator“ log into the router as „labuser“:
      • Manually specify a username to use and gain CLI access
    • $ ssh -l labuser 192.168.56.102
      
      VBOX-CSR-1>who
          Line       User       Host(s)              Idle       Location
         0 con 0                idle                 00:02:43
      *  1 vty 0     labuser    idle                 00:00:00 192.168.56.101
      
    • You don’t want to configure an „enable secret“-password in 2018..
    • VBOX-CSR-1>enable
      % No password set
      
      • configure a local user-privilege or use for example the Cisco ISE for centralized Authorization and additional Accounting if needed.
      • conf t
          username labuser privilege 15
        end
        
      • Check – you’ll access privileged-mode immediately
      • $ ssh -l labuser 192.168.56.102
        
        VBOX-CSR-1#who
            Line       User       Host(s)              Idle       Location
           0 con 0                idle                 00:00:10
        *  1 vty 0     labuser    idle                 00:00:00 192.168.56.101
        
          Interface    User               Mode         Idle     Peer Address
        
        VBOX-CSR-1#show priv
        Current privilege level is 15
        
  6. Prove SSH-Client-access: Windows/Putty
    • Specify the „Auto-Login-Username“: „labuser“
    • Specify the private-key-file (*.ppk)
    • [Open]
      • since the ppk-file was password-protected (in PuttyGen) this password has to be entered:
      • privilege-15 access for the windows-user

      [btw. the linux-ssh-client „labuser“ is still logged in]

That’s all.