Wyróżnione

Networks can be fun (for life)

john_whitelbow

Hi!

I’m a NOC engineer with a passion for languages. I used to be a language teacher but I realized that this was not something that I could do all my life. I joined Nokia in 2009 and now, 10 years later, i’m a senior network engineer at another major IT company, trying to get better with each day of solving network cases.

I’m always open to new challenges so if you’re stuck with a problem, or need a new network design or a quick implementation, drop me a line ( dewilletomek@gmail.com ) or call me on +48601079955.

IPsec preferred peer + reverse route static

Hello

A bit of a pause with automation this week. I’ve been assigned a task to set up a redundant crypto-based VPN, a task which is in fact quite easy but for some weird reason Cisco documentation doesn’t describe how to do this in the peer preferred feature.
The problem is here that you can’t set up static routes with a track object because there’s nothing to link the track object to if you don’t have logical tunnel interfaces. Of course, there’s always EEM scripts that could activate routes if it sees ”tunnel up/down” events in the syslog but… let’s be serious. Besides, I was curious to see how fast this redundancy works.
vpn_redundancy

R1 has 1.1.1.1, both R2 and R3 have 2.2.2.2 as their loopback to simulate redundant LANs behind them (e.g. distributed data center)

crypto isakmp policy 10
encr 3des
authentication pre-share
group 5
crypto isakmp key cisco address 0.0.0.0
crypto isakmp keepalive 10
crypto ipsec transform-set MYSET esp-3des esp-sha-hmac
mode tunnel
crypto map MYMAP 10 ipsec-isakmp
set peer 101.1.1.1 default !!!by default tunnel goes to R2
set peer 102.1.1.1 !!! if keepalives (DPD) to R2 fail, tunnel is initiated to R3
set transform-set MYSET
match address MYACL
reverse-route static !!!this installs routes to 2.2.2.2 dynamically based on ACL and state of DPD
crypto map MYMAP


ip access-list ext MYACL
permit ip host 1.1.1.1 2.2.2.2

int loopback0
ip addr 1.1.1.1 255.255.255.255

 

Now let’s ping 2.2.2.2 from R1’s 1.1.1.1 when R2 and R3 are up with crypto isakmp debug on.

IOU1#ping 2.2.2.2 source 1.1.1.1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 2.2.2.2, timeout is 2 seconds:
Packet sent with a source address of 1.1.1.1

*Aug 7 03:11:44.860: ISAKMP:(0): SA request profile is (NULL)
*Aug 7 03:11:44.860: ISAKMP: Created a peer struct for 101.1.1.1, peer port 500
*Aug 7 03:11:44.860: ISAKMP: New peer created peer = 0xF2F1E4D8 peer_handle = 0x80000006
*Aug 7 03:11:44.860: ISAKMP: Locking peer struct 0xF2F1E4D8, refcount 1 for isakmp_initiator
*Aug 7 03:11:44.860: ISAKMP: local port 500, remote port 500
*Aug 7 03:11:44.860: ISAKMP: set new node 0 to QM_IDLE
*Aug 7 03:11:44.860: ISAKMP: Find a dup sa in the avl tree during calling isadb_insert sa = F2F30F50
*Aug 7 03:11:44.860: ISAKMP:(0):Can not start Aggressive mode, trying Main mode.
*Aug 7 03:11:44.860: ISAKMP:(0):found peer pre-shared key matching 101.1.1.1
*Aug 7 03:11:44.860: ISAKMP:(0): constructed NAT-T vendor-rfc3947 ID
*Aug 7 03:11:44.860: ISAKMP:(0): constructed NAT-T vendor-07 ID
*Aug 7 03:11:44.860: ISAKMP:(0): constructed NAT-T vendor-03 ID
*Aug 7 03:11:44.860: ISAKMP:(0): constructed NAT-T vendor-02 ID
*Aug 7 03:11:44.860: ISAKMP:(0):Input = IKE_MESG_FROM_IPSEC, IKE_SA_REQ_MM
*Aug 7 03:11:44.860: ISAKMP:(0):Old State = IKE_READY New State = IKE_I_MM1

*Aug 7 03:11:44.860: ISAKMP:(0): beginning Main Mode exchange
*Aug 7 03:11:44.860: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:11:44.860: ISAKMP:(0):Sending an IKE IPv4 Packet.
*Aug 7 03:11:44.863: ISAKMP (0): received packet from 101.1.1.1 dport 500 sport 500 Global (I) MM_NO_STATE
*Aug 7 03:11:44.863: ISAKMP:(0):Input = IKE_MESG_FROM_PEER, IKE_MM_EXCH
*Aug 7 03:11:44.863: ISAKMP:(0):Old State = IKE_I_MM1 New State = IKE_I_MM2

*Aug 7 03:11:44.863: ISAKMP:(0): processing SA payload. message ID = 0
*Aug 7 03:11:44.863: ISAKMP:(0): processing vendor id payload
*Aug 7 03:11:44.863: ISAKMP:(0): vendor ID seems Unity/DPD but major 69 mismatch
*Aug 7 03:11:44.863: ISAKMP (0): vendor ID is NAT-T RFC 3947
*Aug 7 03:11:44.863: ISAKMP:(0):found peer pre-shared key matching 101.1.1.1
*Aug 7 03:11:44.863: ISAKMP:(0): local preshared key found
*Aug 7 03:11:44.863: ISAKMP : Scanning profiles for xauth ...
*Aug 7 03:11:44.863: ISAKMP:(0):Checking ISAKMP transform 1 against priority 10 policy
*Aug 7 03:11:44.863: ISAKMP: encryption 3DES-CBC
*Aug 7 03:11:44.863: ISAKMP: hash SHA
*Aug 7 03:11:44.863: ISAKMP: default group 5
*Aug 7 03:11:44.863: ISAKMP: auth pre-share
*Aug 7 03:11:44.863: ISAKMP: life type in seconds
*Aug 7 03:11:44.863: ISAKMP: life duration (VPI) of 0x0 0x1 0x51 0x80
*Aug 7 03:11:44.863: ISAKMP:(0):atts are acceptable. Next payload is 0
*Aug 7 03:11:44.863: ISAKMP:(0):Acceptable atts:actual life: 0
*Aug 7 03:11:44.863: ISAKMP:(0):Acceptable atts:life: 0
*Aug 7 03:11:44.863: ISAKMP:(0):Fill atts in sa vpi_length:4
*Aug 7 03:11:44.863: ISAKMP:(0):Fill atts in sa life_in_seconds:86400
*Aug 7 03:11:44.863: ISAKMP:(0):Returning Actual lifetime: 86400
*Aug 7 03:11:44.863: ISAKMP:(0)::Started lifetime timer: 86400.

*Aug 7 03:11:44.863: ISAKMP:(0): processing vendor id payload
*Aug 7 03:11:44.863: ISAKMP:(0): vendor ID seems Unity/DPD but major 69 mismatch
*Aug 7 03:11:44.863: ISAKMP (0): vendor ID is NAT-T RFC 3947
*Aug 7 03:11:44.863: ISAKMP:(0):Input = IKE_MESG_INTERNAL, IKE_PROCESS_MAIN_MODE
*Aug 7 03:11:44.863: ISAKMP:(0):Old State = IKE_I_MM2 New State = IKE_I_MM2

*Aug 7 03:11:44.863: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_SA_SETUP
*Aug 7 03:11:44.863: ISAKMP:(0):Sending an IKE IPv4 Packet.
*Aug 7 03:11:44.863: ISAKMP:(0):Input = IKE_MESG_INTERNAL, IKE_PROCESS_COMPLETE
*Aug 7 03:11:44.863: ISAKMP:(0):Old State = IKE_I_MM2 New State = IKE_I_MM3

*Aug 7 03:11:44.882: ISAKMP (0): received packet from 101.1.1.1 dport 500 sport 500 Global (I) MM_SA_SETUP
*Aug 7 03:11:44.882: ISAKMP:(0):Input = IKE_MESG_FROM_PEER, IKE_MM_EXCH
*Aug 7 03:11:44.882: ISAKMP:(0):Old State = IKE_I_MM3 New State = IKE_I_MM4

*Aug 7 03:11:44.882: ISAKMP:(0): processing KE payload. message ID = 0
*Aug 7 03:11:44.896: ISAKMP:(0): processing NONCE payload. message ID = 0
*Aug 7 03:11:44.896: ISAKMP:(0):found peer pre-shared key matching 101.1.1.1
*Aug 7 03:11:44.896: ISAKMP:(1004): processing vendor id payload
*Aug 7 03:11:44.896: ISAKMP:(1004): vendor ID is Unity
*Aug 7 03:11:44.896: ISAKMP:(1004): processing vendor id payload
*Aug 7 03:11:44.896: ISAKMP:(1004): vendor ID is DPD
*Aug 7 03:11:44.896: ISAKMP:(1004): processing vendor id payload
*Aug 7 03:11:44.896: ISAKMP:(1004): speaking to another IOS box!
*Aug 7 03:11:44.896: ISAKMP:received payload type 20
*Aug 7 03:11:44.896: ISAKMP (1004): His hash no match - this node outside NAT
*Aug 7 03:11:44.896: ISAKMP:received payload type 20
*Aug 7 03:11:44.896: ISAKMP (1004): No NAT Found for self or peer
*Aug 7 03:11:44.896: ISAKMP:(1004):Input = IKE_MESG_INTERNAL, IKE_PROCESS_MAIN_MODE
*Aug 7 03:11:44.896: ISAKMP:(1004):Old State = IKE_I_MM4 New State = IKE_I_MM4

*Aug 7 03:11:44.897: ISAKMP:(1004):Send initial contact
*Aug 7 03:11:44.897: ISAKMP:(1004):SA is doing pre-shared key authentication using id type ID_IPV4_ADDR
*Aug 7 03:11:44.897: ISAKMP (1004): ID payload
next-payload : 8
type : 1
address : 100.1.1.1
protocol : 17
port : 500
length : 12
*Aug 7 03:11:44.897: ISAKMP:(1004):Total payload length: 12
*Aug 7 03:11:44.897: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_KEY_EXCH
*Aug 7 03:11:44.897: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:11:44.897: ISAKMP:(1004):Input = IKE_MESG_INTERNAL, IKE_PROCESS_COMPLETE
*Aug 7 03:11:44.897: ISAKMP:(1004):Old State = IKE_I_MM4 New State = IKE_I_MM5

*Aug 7 03:11:44.899: ISAKMP (1004): received packet from 101.1.1.1 dport 500 sport 500 Global (I) MM_KEY_EXCH
*Aug 7 03:11:44.899: ISAKMP:(1004): processing ID payload. message ID = 0
*Aug 7 03:11:44.899: ISAKMP (1004): ID payload
next-payload : 8
type : 1
address : 101.1.1.1
protocol : 17
port : 500
length : 12
*Aug 7 03:11:44.899: ISAKMP:(0):: peer matches *none* of the profiles
*Aug 7 03:11:44.899: ISAKMP:(1004): processing HASH payload. message ID = 0
*Aug 7 03:11:44.899: ISAKMP:(1004):SA authentication status:
authenticated
*Aug 7 03:11:44.899: ISAKMP:(1004):SA has been authenticated with 101.1.1.1
*Aug 7 03:11:44.899: ISAKMP: Trying to insert a peer 100.1.1.1/101.1.1.1/500/, and inserted successfully F2F1E4D8.
*Aug 7 03:11:44.899: ISAKMP:(1004):Input = IKE_MESG_FROM_PEER, IKE_MM_EXCH
*Aug 7 03:11:44.899: ISAKMP:(1004):Old State = IKE_I_MM5 New State = IKE_I_MM6

*Aug 7 03:11:44.900: ISAKMP:(1004):Input = IKE_MESG_INTERNAL, IKE_PROCESS_MAIN_MODE
*Aug 7 03:11:44.900: ISAKMP:(1004):Old State = IKE_I_MM6 New State = IKE_I_MM6

*Aug 7 03:11:44.909: ISAKMP:(1004):Input = IKE_MESG_INTERNAL, IKE_PROCESS_COMPLETE
*Aug 7 03:11:44.909: ISAKMP:(1004):Old State = IKE_I_MM6 New State = IKE_P1_COMPLETE

*Aug 7 03:11:44.909: ISAKMP:(1004):IKE_DPD is enabled, initializing timers
*Aug 7 03:11:44.909: ISAKMP:(1004):beginning Quick Mode exchange, M-ID of 3736979590
*Aug 7 03:11:44.909: ISAKMP:(1004):QM Initiator gets spi
*Aug 7 03:11:44.909: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:11:44.909: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:11:44.909: ISAKMP:(1004):Node 3736979590, Input = IKE_MESG_INTERNAL, IKE_INIT_QM
*Aug 7 03:11:44.909: ISAKMP:(1004):Old State = IKE_QM_READY New State = IKE_QM_I_QM1
*Aug 7 03:11:44.909: ISAKMP:(1004):Input = IKE_MESG_INTERNAL, IKE_PHASE1_COMPLETE
*Aug 7 03:11:44.909: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

*Aug 7 03:11:44.913: ISAKMP (1004): received packet from 101.1.1.1 dport 500 sport 500 Global (I) QM_IDLE
*Aug 7 03:11:44.913: ISAKMP:(1004): processing HASH payload. message ID = 3736979590
*Aug 7 03:11:44.913: ISAKMP:(1004): processing SA payload. message ID = 3736979590
*Aug 7 03:11:44.913: ISAKMP:(1004):Checking IPSec proposal 1
*Aug 7 03:11:44.913: ISAKMP: transform 1, ESP_3DES
*Aug 7 03:11:44.913: ISAKMP: attributes in transform:
*Aug 7 03:11:44.913: ISAKMP: encaps is 1 (Tunnel)
*Aug 7 03:11:44.913: ISAKMP: SA life type in seconds
*Aug 7 03:11:44.913: ISAKMP: SA life duration (basic) of 3600
*Aug 7 03:11:44.913: ISAKMP: SA life type in kilobytes
*Aug 7 03:11:44.913: ISAKMP: SA life duration (VPI) of 0x0 0x46 0x50 0x0
*Aug 7 03:11:44.913: ISAKMP: authenticator is HMAC-SHA
*Aug 7 03:11:44.913: ISAKMP:(1004):atts are acceptable.
*Aug 7 03:11:44.913: ISAKMP:(1004): processing NONCE payload. message ID = 3736979590
*Aug 7 03:11:44.913: ISAKMP:(1004): processing ID payload. message ID = 3736979590
*Aug 7 03:11:44.913: ISAKMP:(1004): processing ID payload. message ID = 3736979590
*Aug 7 03:11:44.913: ISAKMP:(1004):Node 3736979590, Input = IKE_MESG_FROM_PEER, IKE_QM_EXCH
*Aug 7 03:11:44.913: ISAKMP:(1004):Old State = IKE_QM_I_QM1 New State = IKE_QM_IPSEC_INSTALL_AWAIT
*Aug 7 03:11:44.913: ISAKMP: Failed to find peer index node to update peer_info_list
*Aug 7 03:11:44.914: ISAKMP:(1004):Received IPSec Install callback... proceeding with the negotiation
*Aug 7 03:11:44.914: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:11:44.914: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:11:44.914: ISAKMP:(1004):deleting node -557987706 error FALSE reason "No Error"
*Aug 7 03:11:44.914: ISAKMP:(1004):Node 3736979590, Input = IKE_MESG_FROM_IPSEC, IPSEC_INSTALL_DONE
*Aug 7 03:11:44.914: ISAKMP:(1004):Old State = IKE_QM_IPSEC_INSTALL_AWAIT New State = IKE_QM_PHASE2_COMPLETE.!!!!
Success rate is 80 percent (4/5), round-trip min/avg/max = 8/12/18 ms
IOU1#
*Aug 7 03:11:57.029: ISAKMP (1004): received packet from 101.1.1.1 dport 500 sport 500 Global (I) QM_IDLE
*Aug 7 03:11:57.029: ISAKMP: set new node 2039185025 to QM_IDLE
*Aug 7 03:11:57.029: ISAKMP:(1004): processing HASH payload. message ID = 2039185025
*Aug 7 03:11:57.029: ISAKMP:(1004): processing NOTIFY DPD/R_U_THERE protocol 1
spi 0, message ID = 2039185025, sa = 0xF2F30F50
*Aug 7 03:11:57.029: ISAKMP:(1004):deleting node 2039185025 error FALSE reason "Informational (in) state 1"
*Aug 7 03:11:57.029: ISAKMP:(1004):Input = IKE_MESG_FROM_PEER, IKE_INFO_NOTIFY
*Aug 7 03:11:57.029: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

*Aug 7 03:11:57.029: ISAKMP:(1004):DPD/R_U_THERE received from peer 101.1.1.1, sequence 0x6EEFB371
*Aug 7 03:11:57.029: ISAKMP: set new node 1411802357 to QM_IDLE
*Aug 7 03:11:57.029: ISAKMP:(1004):Sending NOTIFY DPD/R_U_THERE_ACK protocol 1
spi 4087798040, message ID = 1411802357
*Aug 7 03:11:57.029: ISAKMP:(1004): seq. no 0x6EEFB371
*Aug 7 03:11:57.029: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:11:57.029: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:11:57.030: ISAKMP:(1004):purging node 1411802357
*Aug 7 03:11:57.030: ISAKMP:(1004):Input = IKE_MESG_FROM_PEER, IKE_MESG_KEEP_ALIVE
IOU1#
*Aug 7 03:11:57.030: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

Now on R2 let’s shut down the public facing interface eth0/0 and see what happens on R1.

IOU1#ping 2.2.2.2 source 1.1.1.1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 2.2.2.2, timeout is 2 seconds:
Packet sent with a source address of 1.1.1.1
.....
Success rate is 0 percent (0/5)

*Aug 7 03:14:55.573: ISAKMP: DPD received KMI message.
*Aug 7 03:14:55.573: ISAKMP: set new node 1236715696 to QM_IDLE
*Aug 7 03:14:55.573: ISAKMP:(1004):Sending NOTIFY DPD/R_U_THERE protocol 1
spi 4073138204, message ID = 1236715696
*Aug 7 03:14:55.573: ISAKMP:(1004): seq. no 0x484909A3
*Aug 7 03:14:55.573: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:14:55.574: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:14:55.574: ISAKMP:(1004):purging node 1236715696
IOU1#show ip route
*Aug 7 03:14:57.586: ISAKMP:(1004):DPD incrementing error counter (1/5)
*Aug 7 03:14:57.586: ISAKMP: set new node -140430850 to QM_IDLE
*Aug 7 03:14:57.586: ISAKMP:(1004):Sending NOTIFY DPD/R_U_THERE protocol 1
spi 4087797952, message ID = 4154536446
*Aug 7 03:14:57.586: ISAKMP:(1004): seq. no 0x484909A4
*Aug 7 03:14:57.586: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:14:57.586: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:14:57.586: ISAKMP:(1004):purging node -140430850
*Aug 7 03:14:57.586: ISAKMP:(1004):Input = IKE_MESG_FROM_TIMER, IKE_TIMER_PEERS_ALIVE
IOU1#
*Aug 7 03:14:57.586: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

IOU1#
*Aug 7 03:14:59.592: ISAKMP:(1004):DPD incrementing error counter (2/5)
*Aug 7 03:14:59.592: ISAKMP: set new node 2080816415 to QM_IDLE
*Aug 7 03:14:59.592: ISAKMP:(1004):Sending NOTIFY DPD/R_U_THERE protocol 1
spi 4087797952, message ID = 2080816415
*Aug 7 03:14:59.592: ISAKMP:(1004): seq. no 0x484909A5
*Aug 7 03:14:59.592: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:14:59.592: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:14:59.592: ISAKMP:(1004):purging node 2080816415
*Aug 7 03:14:59.592: ISAKMP:(1004):Input = IKE_MESG_FROM_TIMER, IKE_TIMER_PEERS_ALIVE
IOU1#
*Aug 7 03:14:59.592: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

IOU1#
*Aug 7 03:15:02.855: ISAKMP:(1004):DPD incrementing error counter (3/5)
*Aug 7 03:15:02.855: ISAKMP: set new node 527308109 to QM_IDLE
*Aug 7 03:15:02.855: ISAKMP:(1004):Sending NOTIFY DPD/R_U_THERE protocol 1
spi 4087797952, message ID = 527308109
*Aug 7 03:15:02.855: ISAKMP:(1004): seq. no 0x484909A6
*Aug 7 03:15:02.855: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:15:02.855: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:15:02.855: ISAKMP:(1004):purging node 527308109
*Aug 7 03:15:02.855: ISAKMP:(1004):Input = IKE_MESG_FROM_TIMER, IKE_TIMER_PEERS_ALIVE
IOU1#
*Aug 7 03:15:02.855: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

IOU1#
*Aug 7 03:15:04.855: ISAKMP:(1004):DPD incrementing error counter (4/5)
*Aug 7 03:15:04.855: ISAKMP: set new node -345256241 to QM_IDLE
*Aug 7 03:15:04.855: ISAKMP:(1004):Sending NOTIFY DPD/R_U_THERE protocol 1
spi 4087797952, message ID = 3949711055
*Aug 7 03:15:04.855: ISAKMP:(1004): seq. no 0x484909A7
*Aug 7 03:15:04.855: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:15:04.855: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:15:04.855: ISAKMP:(1004):purging node -345256241
*Aug 7 03:15:04.855: ISAKMP:(1004):Input = IKE_MESG_FROM_TIMER, IKE_TIMER_PEERS_ALIVE
IOU1#
*Aug 7 03:15:04.855: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

IOU1#
*Aug 7 03:15:06.860: ISAKMP:(1004):DPD incrementing error counter (5/5)
*Aug 7 03:15:06.860: ISAKMP:(1004):peer 101.1.1.1 not responding!
*Aug 7 03:15:06.860: ISAKMP:(1004):peer does not do paranoid keepalives.

*Aug 7 03:15:06.860: ISAKMP:(1004):deleting SA reason "End of ipsec tunnel" state (I) QM_IDLE (peer 101.1.1.1)
*Aug 7 03:15:06.860: ISAKMP:(1004):Input = IKE_MESG_FROM_TIMER, IKE_TIMER_PEERS_ALIVE
*Aug 7 03:15:06.860: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

*Aug 7 03:15:06.860: ISAKMP: Failed to find peer index node to update peer_info_list
*Aug 7 03:15:06.860: ISAKMP: set new node 186812859 to QM_IDLE
*Aug 7 03:15:06.861: ISAKMP:(1004): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:15:06.861: ISAKMP:(1004):Sending an IKE IPv4 Packet.
*Aug 7 03:15:06.861: ISAKMP:(1004):purging node 186812859
*Aug 7 03:15:06.861: ISAKMP:(1004):Input = IKE_MESG_INTERNAL, IKE_PHASE1_DEL
*Aug 7 03:15:06.861: ISAKMP:(1004):Old State = IKE_P1_COMPLETE New State = IKE_DEST_SA

*Aug 7 03:15:06.861: ISAKMP:(1004):deleting SA reason "End of ipsec tunnel" state (I) QM_IDLE (peer 101.1.1.1)
*Aug 7 03:15:06.861: ISAKMP: Unlocking peer struct 0xF2F1E4D8 for isadb_mark_sa_deleted(), count 0
IOU1#
*Aug 7 03:15:06.861: ISAKMP:(1004):Input = IKE_MESG_FROM_PEER, IKE_MM_EXCH
*Aug 7 03:15:06.861: ISAKMP:(1004):Old State = IKE_DEST_SA New State = IKE_DEST_SA

*Aug 7 03:15:06.988: ISAKMP: Deleting peer node by peer_reap for 101.1.1.1: F2F1E4D8
*Aug 7 03:15:06.988: ISAKMP: ignoring request to send delete notify (no ISAKMP sa) src 100.1.1.1 dst 101.1.1.1 for SPI 0xA9FAAD12
IOU1#ping 2.2.2.2 source 1.1.1.1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 2.2.2.2, timeout is 2 seconds:
Packet sent with a source address of 1.1.1.1

*Aug 7 03:15:26.674: ISAKMP:(0): SA request profile is (NULL)
*Aug 7 03:15:26.674: ISAKMP: Created a peer struct for 101.1.1.1, peer port 500
*Aug 7 03:15:26.674: ISAKMP: New peer created peer = 0xF2F1E4D8 peer_handle = 0x80000007
*Aug 7 03:15:26.674: ISAKMP: Locking peer struct 0xF2F1E4D8, refcount 1 for isakmp_initiator
*Aug 7 03:15:26.674: ISAKMP: local port 500, remote port 500
*Aug 7 03:15:26.674: ISAKMP: set new node 0 to QM_IDLE
*Aug 7 03:15:26.674: ISAKMP: Find a dup sa in the avl tree during calling isadb_insert sa = F4AB36C8
*Aug 7 03:15:26.674: ISAKMP:(0):Can not start Aggressive mode, trying Main mode.
*Aug 7 03:15:26.674: ISAKMP:(0):found peer pre-shared key matching 101.1.1.1
*Aug 7 03:15:26.674: ISAKMP:(0): constructed NAT-T vendor-rfc3947 ID
*Aug 7 03:15:26.674: ISAKMP:(0): constructed NAT-T vendor-07 ID
*Aug 7 03:15:26.674: ISAKMP:(0): constructed NAT-T vendor-03 ID
*Aug 7 03:15:26.674: ISAKMP:(0): constructed NAT-T vendor-02 ID
*Aug 7 03:15:26.674: ISAKMP:(0):Input = IKE_MESG_FROM_IPSEC, IKE_SA_REQ_MM
*Aug 7 03:15:26.674: ISAKMP:(0):Old State = IKE_READY New State = IKE_I_MM1

*Aug 7 03:15:26.674: ISAKMP:(0): beginning Main Mode exchange
*Aug 7 03:15:26.674: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:15:26.674: ISAKMP:(0):Sending an IKE IPv4 Packet......
Success rate is 0 percent (0/5)
IOU1#
*Aug 7 03:15:36.676: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE...
*Aug 7 03:15:36.676: ISAKMP (0): incrementing error counter on sa, attempt 1 of 5: retransmit phase 1
*Aug 7 03:15:36.676: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE
*Aug 7 03:15:36.676: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:15:36.676: ISAKMP:(0):Sending an IKE IPv4 Packet.
IOU1#
*Aug 7 03:15:46.684: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE...
*Aug 7 03:15:46.684: ISAKMP (0): incrementing error counter on sa, attempt 2 of 5: retransmit phase 1
*Aug 7 03:15:46.684: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE
*Aug 7 03:15:46.684: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:15:46.684: ISAKMP:(0):Sending an IKE IPv4 Packet.
IOU1#
*Aug 7 03:15:56.676: ISAKMP: set new node 0 to QM_IDLE
*Aug 7 03:15:56.676: ISAKMP:(0):SA is still budding. Attached new ipsec request to it. (local 100.1.1.1, remote 101.1.1.1)
*Aug 7 03:15:56.676: ISAKMP: Error while processing SA request: Failed to initialize SA
*Aug 7 03:15:56.676: ISAKMP: Error while processing KMI message 0, error 2.
*Aug 7 03:15:56.693: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE...
*Aug 7 03:15:56.693: ISAKMP (0): incrementing error counter on sa, attempt 3 of 5: retransmit phase 1
*Aug 7 03:15:56.693: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE
IOU1#
*Aug 7 03:15:56.693: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:15:56.693: ISAKMP:(0):Sending an IKE IPv4 Packet.
IOU1#
*Aug 7 03:16:06.698: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE...
*Aug 7 03:16:06.698: ISAKMP (0): incrementing error counter on sa, attempt 4 of 5: retransmit phase 1
*Aug 7 03:16:06.698: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE
*Aug 7 03:16:06.698: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:16:06.698: ISAKMP:(0):Sending an IKE IPv4 Packet.
*Aug 7 03:16:06.865: ISAKMP:(1004):purging SA., sa=F2F30F50, delme=F2F30F50
IOU1#
*Aug 7 03:16:16.699: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE...
*Aug 7 03:16:16.699: ISAKMP (0): incrementing error counter on sa, attempt 5 of 5: retransmit phase 1
*Aug 7 03:16:16.699: ISAKMP:(0): retransmitting phase 1 MM_NO_STATE
*Aug 7 03:16:16.699: ISAKMP:(0): sending packet to 101.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:16:16.699: ISAKMP:(0):Sending an IKE IPv4 Packet.
IOU1#
*Aug 7 03:16:26.682: ISAKMP:(0):peer does not do paranoid keepalives.

*Aug 7 03:16:26.682: ISAKMP:(0):deleting SA reason "P1 delete notify (in)" state (I) MM_NO_STATE (peer 101.1.1.1)
*Aug 7 03:16:26.682: ISAKMP:(0): SA request profile is (NULL)
*Aug 7 03:16:26.682: ISAKMP: Created a peer struct for 102.1.1.1, peer port 500
*Aug 7 03:16:26.682: ISAKMP: New peer created peer = 0xF4A92B30 peer_handle = 0x80000008
*Aug 7 03:16:26.682: ISAKMP: Locking peer struct 0xF4A92B30, refcount 1 for isakmp_initiator
*Aug 7 03:16:26.682: ISAKMP: local port 500, remote port 500
*Aug 7 03:16:26.682: ISAKMP: set new node 0 to QM_IDLE
*Aug 7 03:16:26.682: ISAKMP:(0):insert sa successfully sa = F2F30F50
*Aug 7 03:16:26.682: ISAKMP:(0):Can not start Aggressive mode, trying Main mode.
*Aug 7 03:16:26.682: ISAKMP:(0):found peer pre-shared key matching 102.1.1.1
*Aug 7 03:16:26.682: ISAKMP:(0): constructed NAT-T vendor-rfc3947 ID
*Aug 7 03:16:26.682: ISAKMP:(0): constructed NAT-T vendor-07 ID
*Aug 7 03:16:26.682: ISAKMP:(0): constructed NAT-T vendor-03 ID
*Aug 7 03:16:26.682: ISAKMP:(0): constructed NAT-T vendor-02 ID
*Aug 7 03:16:26.682: ISAKMP:(0):Input = IKE_MESG_FROM_IPSEC, IKE_SA_REQ_MM
*Aug 7 03:16:26.682: ISAKMP:(0):Old State = IKE_READY New State = IKE_I_MM1

*Aug 7 03:16:26.682: ISAKMP:(0): beginning Main Mode exchange
*Aug 7 03:16:26.682: ISAKMP:(0): sending packet to 102.1.1.1 my_port 500 peer_port 500 (I) MM_NO_STATE
*Aug 7 03:16:26.682: ISAKMP:(0):Sending an IKE IPv4 Packet.
*Aug 7 03:16:26.682: ISAKMP:(0):deleting SA reason "P1 delete notify (in)" state (I) MM_NO_STATE (peer 101.1.1.1)
*Aug 7 03:16:26.682: ISAKMP: Unlocking peer struct 0xF2F1E4D8 for isadb_mark_sa_deleted(), count 0
*Aug 7 03:16:26.682: ISAKMP: Deleting peer node by peer_reap for 101.1.1.1: F2F1E4D8
*Aug 7 03:16:26.683: ISAKMP:(0):deleting node 189642018 error FALSE reason "IKE deleted"
*Aug 7 03:16:26.683: ISAKMP:(0):deleting node -162170267 error FALSE reason "IKE deleted"
*Aug 7 03:16:26.683: ISAKMP:(0):Input = IKE_MESG_INTERNAL, IKE_PHASE1_DEL
*Aug 7 03:16:26.683: ISAKMP:(0):Old State = IKE_I_MM1 New State = IKE_DEST_SA

*Aug 7 03:16:26.684: ISAKMP (0): received packet from 102.1.1.1 dport 500 sport 500 Global (I) MM_NO_STATE
*Aug 7 03:16:26.684: ISAKMP:(0):Input = IKE_MESG_FROM_PEER, IKE_MM_EXCH
*Aug 7 03:16:26.684: ISAKMP:(0):Old State = IKE_I_MM1 New State = IKE_I_MM2

*Aug 7 03:16:26.684: ISAKMP:(0): processing SA payload. message ID = 0
*Aug 7 03:16:26.684: ISAKMP:(0): processing vendor id payload
*Aug 7 03:16:26.684: ISAKMP:(0): vendor ID seems Unity/DPD but major 69 mismatch
*Aug 7 03:16:26.684: ISAKMP (0): vendor ID is NAT-T RFC 3947
*Aug 7 03:16:26.684: ISAKMP:(0):found peer pre-shared key matching 102.1.1.1
*Aug 7 03:16:26.684: ISAKMP:(0): local preshared key found
*Aug 7 03:16:26.684: ISAKMP : Scanning profiles for xauth ...
*Aug 7 03:16:26.684: ISAKMP:(0):Checking ISAKMP transform 1 against priority 10 policy
*Aug 7 03:16:26.684: ISAKMP: encryption 3DES-CBC
*Aug 7 03:16:26.684: ISAKMP: hash SHA
*Aug 7 03:16:26.684: ISAKMP: default group 5
*Aug 7 03:16:26.684: ISAKMP: auth pre-share
*Aug 7 03:16:26.684: ISAKMP: life type in seconds
*Aug 7 03:16:26.684: ISAKMP: life duration (VPI) of 0x0 0x1 0x51 0x80
*Aug 7 03:16:26.684: ISAKMP:(0):atts are acceptable. Next payload is 0
*Aug 7 03:16:26.684: ISAKMP:(0):Acceptable atts:actual life: 0
*Aug 7 03:16:26.684: ISAKMP:(0):Acceptable atts:life: 0
*Aug 7 03:16:26.684: ISAKMP:(0):Fill atts in sa vpi_length:4
*Aug 7 03:16:26.684: ISAKMP:(0):Fill atts in sa life_in_seconds:86400
*Aug 7 03:16:26.684: ISAKMP:(0):Returning Actual lifetime: 86400
*Aug 7 03:16:26.684: ISAKMP:(0)::Started lifetime timer: 86400.

*Aug 7 03:16:26.684: ISAKMP:(0): processing vendor id payload
*Aug 7 03:16:26.684: ISAKMP:(0): vendor ID seems Unity/DPD but major 69 mismatch
*Aug 7 03:16:26.684: ISAKMP (0): vendor ID is NAT-T RFC 3947
*Aug 7 03:16:26.684: ISAKMP:(0):Input = IKE_MESG_INTERNAL, IKE_PROCESS_MAIN_MODE
*Aug 7 03:16:26.684: ISAKMP:(0):Old State = IKE_I_MM2 New State = IKE_I_MM2

*Aug 7 03:16:26.684: ISAKMP:(0): sending packet to 102.1.1.1 my_port 500 peer_port 500 (I) MM_SA_SETUP
*Aug 7 03:16:26.684: ISAKMP:(0):Sending an IKE IPv4 Packet.
*Aug 7 03:16:26.684: ISAKMP:(0):Input = IKE_MESG_INTERNAL, IKE_PROCESS_COMPLETE
*Aug 7 03:16:26.684: ISAKMP:(0):Old State = IKE_I_MM2 New State = IKE_I_MM3

*Aug 7 03:16:26.698: ISAKMP (0): received packet from 102.1.1.1 dport 500 sport 500 Global (I) MM_SA_SETUP
*Aug 7 03:16:26.698: ISAKMP:(0):Input = IKE_MESG_FROM_PEER, IKE_MM_EXCH
*Aug 7 03:16:26.698: ISAKMP:(0):Old State = IKE_I_MM3 New State = IKE_I_MM4

*Aug 7 03:16:26.698: ISAKMP:(0): processing KE payload. message ID = 0
*Aug 7 03:16:26.709: ISAKMP:(0): processing NONCE payload. message ID = 0
*Aug 7 03:16:26.709: ISAKMP:(0):found peer pre-shared key matching 102.1.1.1
*Aug 7 03:16:26.709: ISAKMP:(1005): processing vendor id payload
*Aug 7 03:16:26.709: ISAKMP:(1005): vendor ID is Unity
*Aug 7 03:16:26.709: ISAKMP:(1005): processing vendor id payload
*Aug 7 03:16:26.709: ISAKMP:(1005): vendor ID is DPD
*Aug 7 03:16:26.709: ISAKMP:(1005): processing vendor id payload
*Aug 7 03:16:26.709: ISAKMP:(1005): speaking to another IOS box!
*Aug 7 03:16:26.709: ISAKMP:received payload type 20
*Aug 7 03:16:26.709: ISAKMP (1005): His hash no match - this node outside NAT
*Aug 7 03:16:26.709: ISAKMP:received payload type 20
*Aug 7 03:16:26.709: ISAKMP (1005): No NAT Found for self or peer
*Aug 7 03:16:26.709: ISAKMP:(1005):Input = IKE_MESG_INTERNAL, IKE_PROCESS_MAIN_MODE
*Aug 7 03:16:26.709: ISAKMP:(1005):Old State = IKE_I_MM4 New State = IKE_I_MM4

*Aug 7 03:16:26.709: ISAKMP:(1005):Send initial contact
*Aug 7 03:16:26.709: ISAKMP:(1005):SA is doing pre-shared key authentication using id type ID_IPV4_ADDR
*Aug 7 03:16:26.709: ISAKMP (1005): ID payload
next-payload : 8
type : 1
address : 100.1.1.1
protocol : 17
port : 500
length : 12
*Aug 7 03:16:26.709: ISAKMP:(1005):Total payload length: 12
*Aug 7 03:16:26.709: ISAKMP:(1005): sending packet to 102.1.1.1 my_port 500 peer_port 500 (I) MM_KEY_EXCH
*Aug 7 03:16:26.709: ISAKMP:(1005):Sending an IKE IPv4 Packet.
*Aug 7 03:16:26.710: ISAKMP:(1005):Input = IKE_MESG_INTERNAL, IKE_PROCESS_COMPLETE
*Aug 7 03:16:26.710: ISAKMP:(1005):Old State = IKE_I_MM4 New State = IKE_I_MM5

*Aug 7 03:16:26.711: ISAKMP (1005): received packet from 102.1.1.1 dport 500 sport 500 Global (I) MM_KEY_EXCH
*Aug 7 03:16:26.711: ISAKMP:(1005): processing ID payload. message ID = 0
*Aug 7 03:16:26.711: ISAKMP (1005): ID payload
next-payload : 8
type : 1
address : 102.1.1.1
protocol : 17
port : 500
length : 12
*Aug 7 03:16:26.711: ISAKMP:(0):: peer matches *none* of the profiles
*Aug 7 03:16:26.711: ISAKMP:(1005): processing HASH payload. message ID = 0
*Aug 7 03:16:26.711: ISAKMP:(1005):SA authentication status:
authenticated
*Aug 7 03:16:26.711: ISAKMP:(1005):SA has been authenticated with 102.1.1.1
*Aug 7 03:16:26.711: ISAKMP: Trying to insert a peer 100.1.1.1/102.1.1.1/500/, and inserted successfully F4A92B30.
*Aug 7 03:16:26.711: ISAKMP:(1005):Input = IKE_MESG_FROM_PEER, IKE_MM_EXCH
*Aug 7 03:16:26.711: ISAKMP:(1005):Old State = IKE_I_MM5 New State = IKE_I_MM6

*Aug 7 03:16:26.711: ISAKMP:(1005):Input = IKE_MESG_INTERNAL, IKE_PROCESS_MAIN_MODE
*Aug 7 03:16:26.711: ISAKMP:(1005):Old State = IKE_I_MM6 New State = IKE_I_MM6

*Aug 7 03:16:26.717: ISAKMP:(1005):Input = IKE_MESG_INTERNAL, IKE_PROCESS_COMPLETE
*Aug 7 03:16:26.717: ISAKMP:(1005):Old State = IKE_I_MM6 New State = IKE_P1_COMPLETE

*Aug 7 03:16:26.717: ISAKMP:(1005):IKE_DPD is enabled, initializing timers
*Aug 7 03:16:26.717: ISAKMP:(1005):beginning Quick Mode exchange, M-ID of 777919085
*Aug 7 03:16:26.717: ISAKMP:(1005):QM Initiator gets spi
*Aug 7 03:16:26.717: ISAKMP:(1005): sending packet to 102.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:16:26.717: ISAKMP:(1005):Sending an IKE IPv4 Packet.
*Aug 7 03:16:26.717: ISAKMP:(1005):Node 777919085, Input = IKE_MESG_INTERNAL, IKE_INIT_QM
*Aug 7 03:16:26.717: ISAKMP:(1005):Old State = IKE_QM_READY New State = IKE_QM_I_QM1
*Aug 7 03:16:26.717: ISAKMP:(1005):Input = IKE_MESG_INTERNAL, IKE_PHASE1_COMPLETE
*Aug 7 03:16:26.717: ISAKMP:(1005):Old State = IKE_P1_COMPLETE New State = IKE_P1_COMPLETE

*Aug 7 03:16:26.719: ISAKMP (1005): received packet from 102.1.1.1 dport 500 sport 500 Global (I) QM_IDLE
*Aug 7 03:16:26.719: ISAKMP:(1005): processing HASH payload. message ID = 777919085
*Aug 7 03:16:26.719: ISAKMP:(1005): processing SA payload. message ID = 777919085
*Aug 7 03:16:26.719: ISAKMP:(1005):Checking IPSec proposal 1
*Aug 7 03:16:26.719: ISAKMP: transform 1, ESP_3DES
*Aug 7 03:16:26.719: ISAKMP: attributes in transform:
*Aug 7 03:16:26.719: ISAKMP: encaps is 1 (Tunnel)
*Aug 7 03:16:26.719: ISAKMP: SA life type in seconds
*Aug 7 03:16:26.719: ISAKMP: SA life duration (basic) of 3600
*Aug 7 03:16:26.719: ISAKMP: SA life type in kilobytes
*Aug 7 03:16:26.719: ISAKMP: SA life duration (VPI) of 0x0 0x46 0x50 0x0
*Aug 7 03:16:26.719: ISAKMP: authenticator is HMAC-SHA
*Aug 7 03:16:26.719: ISAKMP:(1005):atts are acceptable.
*Aug 7 03:16:26.719: ISAKMP:(1005): processing NONCE payload. message ID = 777919085
*Aug 7 03:16:26.719: ISAKMP:(1005): processing ID payload. message ID = 777919085
*Aug 7 03:16:26.719: ISAKMP:(1005): processing ID payload. message ID = 777919085
*Aug 7 03:16:26.719: ISAKMP:(1005):Node 777919085, Input = IKE_MESG_FROM_PEER, IKE_QM_EXCH
*Aug 7 03:16:26.719: ISAKMP:(1005):Old State = IKE_QM_I_QM1 New State = IKE_QM_IPSEC_INSTALL_AWAIT
*Aug 7 03:16:26.720: ISAKMP: Failed to find peer index node to update peer_info_list
*Aug 7 03:16:26.720: ISAKMP:(1005):Received IPSec Install callback... proceeding with the negotiation
*Aug 7 03:16:26.720: ISAKMP:(1005): sending packet to 102.1.1.1 my_port 500 peer_port 500 (I) QM_IDLE
*Aug 7 03:16:26.720: ISAKMP:(1005):Sending an IKE IPv4 Packet.
*Aug 7 03:16:26.720: ISAKMP:(1005):deleting node 777919085 error FALSE reason "No Error"
*Aug 7 03:16:26.720: ISAKMP:(1005):Node 777919085, Input = IKE_MESG_FROM_IPSEC, IPSEC_INSTALL_DONE
IOU1#
*Aug 7 03:16:26.720: ISAKMP:(1005):Old State = IKE_QM_IPSEC_INSTALL_AWAIT New State = IKE_QM_PHASE2_COMPLETE
IOU1#


 

It’s interesting to see how much time elapsed: a lot! I shut down the interface at around 3:14:40. The DPD realized there’s a problem at 3:14:55 so it started sending keepalives every 2 seconds. It gave up at 3:15:06. This is already 26 seconds. I pinged 2.2.2.2 again at 3:15:26, R2 didn’t respond so isakmp gave up after another minute and only then did it probe R3. This gives us around 90 seconds of delay in case of a failure of the primary vpn peer.

 

Implementation and verification solutions

Hello

I’ve been looking at existing automation solutions for a while now and it seems I have the following options now:

IMPLEMENTATION:

  • netmiko + yaml
  • Unicon (pyATS transport plugin) + yaml.
  • Ansible
  • nornir
  • napalm

VERIFICATION AND DATA EXTRACTION:

  • pyATS
  • netmiko

The problem that I’m dealing at work is that i have a custom bastion that i need to traverse to get to my managed network devices. I will therefore try to implement a few designs (acl add, acl delete, vlan add, vpn add, route add etc.) using each of the implementation solutions, first without and then with the custom proxy. I’ll try to compare the effort to implement and verify. (And yes, I do realize that the final goal should be a continouos integration solution like Jenkins but hey, Rome wasn’t build in a day)

 

 

 

Implementing ACLs using Netmiko or Unicon or Ansible – which is easier?

Hello

Today I wanted to play a bit with implementing config using either netmiko or unicon together with .j2 templates:

I first launched GNS3 on ubuntu 20.04 and prepared a simple topology

GNS3_netmiko

I connected ubuntu to gns3 using the nat cloud. R1 is 192.168.122.100.

NETMIKO

My goal was to implement a simple ACL on R1. To do that, i’ve prepared an acl.j2 template file:

{% for accesslist in data.accesslists %}
ip access-list extended {{accesslist.aclname}}
{{accesslist.aclcommand}} {{accesslist.protocol}} {{accesslist.source}} {{accesslist.sourcewildcard}} {{accesslist.destination}} {{accesslist.destwildcard}}
{% endfor %}

Then I prepared the acl data in the acl.yml file:

accesslists:
- aclname: permit_www
aclcommand: permit
protocol: ip
source: 192.168.122.100
sourcewildcard: 0.0.0.0
destination: 8.8.8.8
destwildcard: 0.0.0.0

Finally, the python script.

import sys
from netmiko import ConnectHandler
import time
from netmiko import redispatch
from netmiko import Netmiko
from jinja2 import Environment, FileSystemLoader
import yaml

def connect(hostip):

net_connect = ConnectHandler(device_type='cisco_ios', host=hostip, username='cisco', password='cisco', secret='cisco')
net_connect.find_prompt()
net_connect.enable()
accesslists = yaml.load(open('acl.yml'), Loader=yaml.SafeLoader)

env = Environment(loader = FileSystemLoader('.'), trim_blocks=True, autoescape=True)
template = env.get_template('acl.j2')
acl_config = template.render(data=accesslists)
print(acl_config)
print(f"Logged into {hostip} successfully")
output = net_connect.send_config_set(acl_config.split("\n"))
if __name__ == "__main__":
ip = sys.argv[1] 
connect(ip)

I then ran the script:

tode@ubuntu:~/nmikoymlproj$ python3 firstscript.py 192.168.122.100
ip access-list extended permit_www
permit ip 192.168.122.100 0.0.0.0 8.8.8.8 0.0.0.0

Logged into 192.168.122.100 successfully


 

UNICON

from unicon import Connection
import time
from jinja2 import Environment, FileSystemLoader
import yaml

#this prepares the config
accesslists = yaml.load(open('acl2.yml'), Loader=yaml.SafeLoader)
env = Environment(loader = FileSystemLoader('.'), trim_blocks=True, autoescape=True)
template = env.get_template('acl.j2')
acl2_config = template.render(data=accesslists)
preoutput = acl2_config.split("\n")

#this prepares the connection
c = Connection(hostname='R1', start=['telnet ' + router1], os='ios', credentials={'default': {'username': 'cisco', 'password': 'cisco'}, 'secret': 'cisco'},)
c.connect()

#This checks how many commands the config set has. This is because unicon's configure method adds ''end'' after each command. So in case of nested commands we need to push the whole set of commands (e.g. interface loop0,ip addr 1.1.1.1 255.255.255.255). So command is a list, to which I push all elements of the config, then the whole list is pushed to the router.

x = len(preoutput)
y=0
command = []
while y<x:
  command.append(preoutput[x-x+y])
  y = y+1

#this actually configures the router
print(command)output = c.configure(command)

and the output…

tode@ubuntu:~/nmikoymlproj$ python3 uniconscript.py

2020-08-03 04:12:14,672: %UNICON-INFO: +++ R1 logfile /tmp/R1-20200803T041214670.log +++

2020-08-03 04:12:14,672: %UNICON-INFO: +++ Unicon plugin ios +++
ip access-list extended permit_www
permit ip 192.168.122.220 0.0.0.0 9.9.9.9 0.0.0.0

Logged into 192.168.122.100 successfully
Trying 192.168.122.100...


2020-08-03 04:12:14,706: %UNICON-INFO: +++ connection to spawn: telnet 192.168.122.100, id: 140510945062576 +++

2020-08-03 04:12:14,707: %UNICON-INFO: connection to R1
Connected to 192.168.122.100.
Escape character is '^]'.


User Access Verification

Username: cisco
Password: 
R1#

2020-08-03 04:12:15,391: %UNICON-INFO: +++ initializing handle +++

2020-08-03 04:12:15,391: %UNICON-INFO: +++ R1: executing command 'term length 0' +++
term length 0
R1#

2020-08-03 04:12:15,510: %UNICON-INFO: +++ R1: executing command 'term width 0' +++
term width 0
R1#

2020-08-03 04:12:15,670: %UNICON-INFO: +++ R1: executing command 'show version' +++
show version
Cisco IOS Software, 7200 Software (C7200-ADVENTERPRISEK9-M), Version 12.4(24)T5, RELEASE SOFTWARE (fc3)
Technical Support: http://www.cisco.com/techsupport

(...)

Configuration register is 0x2102

R1#

2020-08-03 04:12:15,820: %UNICON-INFO: +++ R1: config +++
config term
Enter configuration commands, one per line.  End with CNTL/Z.
R1(config)#no logging console
R1(config)#line console 0
R1(config-line)#exec-timeout 0
R1(config-line)#end
R1#
['ip access-list extended permit_www', 'permit ip 192.168.122.220 0.0.0.0 9.9.9.9 0.0.0.0', '']

2020-08-03 04:12:16,007: %UNICON-INFO: +++ R1: config +++
config term
Enter configuration commands, one per line.  End with CNTL/Z.
R1(config)#ip access-list extended permit_www
R1(config-ext-nacl)#permit ip 192.168.122.220 0.0.0.0 9.9.9.9 0.0.0.0
R1(config-ext-nacl)#end
R1#

 

Now let’s take the hosts into an inventory yml file:

from unicon import Connection
from jinja2 import Environment, FileSystemLoader
import yaml
from pyats.topology import loader

#this prepares the config and command sets
accesslists = yaml.load(open('acl2.yml'), Loader=yaml.SafeLoader)
env = Environment(loader = FileSystemLoader('.'), trim_blocks=True, autoescape=True)
template = env.get_template('acl.j2')
acl2_config = template.render(data=accesslists)
preoutput = acl2_config.split("\n")
x = len(preoutput)
y=0
command = []
while y<x:
  command.append(preoutput[x-x+y])
  y = y+1

#this loads the testbed topology and connects
testbed = loader.load("testbed.yml")
c = testbed.devices['R1']
c.connect()

#actual configuration
output = c.configure(command)

where the inventory file looks as follows:

devices:
    R1:
       connections:
          cli:
             ip: 192.168.122.100
             port: 23 
             protocol: telnet
      credentials:
         default:
             password: cisco
             username: cisco
         enable:
              password: cisco
     os: ios
     type: ios

 

Now this code is still not ideal because too many things are hardcoded:

  • acl.j2 template
  • acl.yml file with the config
  • name of router from the testbed

So let’s do move them out into sys.args + a bit of refactoring to have everything neat

def prepareconfig(template,configdata):
  accesslists = yaml.load(open(configdata), Loader=yaml.SafeLoader)
  env = Environment(loader = FileSystemLoader('.'), trim_blocks=True, autoescape=True)
  template = env.get_template(template)
  realconfig = template.render(data=accesslists)
  preoutput = realconfig.split("\n")
  x = len(preoutput)
  y=0
  command = []
  while y<x:
     command.append(preoutput[x-x+y])
     y = y+1
  return command

def connect(testbedfile,devicename):
  testbed = loader.load(testbedfile)
  c = testbed.devices[devicename]
  c.connect()
  return c

def configure(command,connection):
  thiscommand = command
  c = connection
  output = c.configure(thiscommand)

##USAGE   python3 script.py acl.j2 acl.yml R1 testbed.yml

if __name__ == "__main__":
  template = sys.argv[1]
  configdata = sys.argv[2]
  devicename = sys.argv[3]
  testbedfile = sys.argv[4]
  configure(prepareconfig(template,configdata),connect(testbedfile,devicename))



This seems quite easy, but for every feature it is necessary to come up with a .j2 template and prepare data according to the template.

ANSIBLE

- name: add_entry_to_acl 
hosts: testrouter
tasks:
- name: add_new_entry
ios_config: 
lines:
- permit ip 10.10.10.10 0.0.0.0 11.11.11.11 0.0.0.0
parents: ip access-list extended permit_www
before: ip access-list extended permit_www
match: exact
authorize: yes

well ain’t that faster than typing up all that python code myself…

Obviously there are things hardcoded in this so let’s do some more work here.

I’ve added an acl20 var to my testrouter.yml under host_vars and changed the playbook in the following way:

- name: modify_acl_entries
  hosts: testrouter
  tasks:
  - name: add_new_entry
    ios_config: 
    lines:
     - "{{ acl20 }}" 
    parents: ip access-list extended permit_www
    before: ip access-list extended permit_www
    save_when: modified

and the output is…

tode@ubuntu:~/ansiblefolder$ ansible-playbook aclplaybook.yml

PLAY [modify_acl_entries] ********************************************************

TASK [add_new_entry] ***********************************************************
[DEPRECATION WARNING]: Distribution Ubuntu 20.04 on host testrouter should use 
/usr/bin/python3, but is using /usr/bin/python for backward compatibility with 
prior Ansible releases. A future Ansible release will default to using the 
discovered platform python for this host. See https://docs.ansible.com/ansible/
2.9/reference_appendices/interpreter_discovery.html for more information. This 
feature will be removed in version 2.12. Deprecation warnings can be disabled 
by setting deprecation_warnings=False in ansible.cfg.
changed: [testrouter]

PLAY RECAP *********************************************************************
testrouter : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

The next step should be to move the task from the playbook and create a role out of it, then the playbook should only contain the role, e.g. ACLmanagement:

- name:  aclplaybook
  hosts: testrouter 
  roles: 
    - aclmanagement

 

#TODOs handlers


 

 

pyATS + unicon = great way of jumping through SSH proxies and bastions

Hello

For the last year i’ve been trying to find a way to implement yaml-based configs on my routers located behind a non-typical jumphost. On this jumphost i need to type „connect <hostname>” to get to my routers. Ansible cannot do this by default because it uses paramiko or native SSH to connect to devices.
Today i’ve found the Unicon library used in pyAts. The code turned out to be super easy:

from unicon import Connection

proxy_conn = Connection(hostname='mybastion', start=['ssh myusername@1.1.1.1 -p 722'], os='linux', credentials={'default': {'username': 'admin', 'password': 'mystupidpassword'}})

c = Connection(hostname='Router1', start=['connect Router1'], os='ios', proxy_connections=[proxy_conn])
c.connect()

As easy as pie. This works on my ubuntu 16.04 with python 3.8. Unfortunately, this works neither in Windows python nor on Ubuntu WSL. (I’m pretty sure it will work in WSL 2 when my windows is updated to windows 10 2004 version, we’ll see).
The next step will be to do the same in yaml, then prepare a playbook in yaml (or whatever pyats calls the task lists).

The example on unicon website looks like this so i suspect something similar:

devices:
  jumphost:
    os: linux
    type: linux
    connections:
      cli:
        protocol: ssh
        ip: 1.1.1.1
        port: 722
  Router:
    os: ios
    type: router
    connections:
      defaults:
        class: unicon.Unicon
      cli:
        command: connect Router1
        proxy: jumphost

Screen scraping made dignified with textfsm templates

Hello

This time I tried out some ready-made templates that some folks prepare to process cisco show command outputs:

from ntc_templates.parse import parse_output
vlan_output = (
„VLAN Name Status Ports\n”
„—- ——————————– ——— ——————————-\n”
„1 default active Gi0/1\n”
„10 Management active \n”
„50 VLan50 active Fa0/1, Fa0/2, Fa0/3, Fa0/4, Fa0/5,\n”
” Fa0/6, Fa0/7, Fa0/8\n”
)
vlan_parsed = parse_output(platform=”cisco_ios”, command=”show vlan”, data=vlan_output)

!!!the output gave us a list of dictionaries that we need to loop through.
In the first step we see that length of vlan_parsed is 3, so we can loop through that.

When we are inside the first loop, we have dictionary objects, so we can use the .items function to go through that, just remembering that because we are inside of the first loop we need to call this by list[x].

x = 0
while x <len(vlan_parsed):
  print()
  print()
  print('NEXT VLAN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
  print()
  for key, value in vlan_parsed[x].items():
     print('---------------------------------')
     print(key, ' : ', value)
  x += 1

And voila!

NEXT VLAN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

———————————
status : active
———————————
name : default
———————————
vlan_id : 1
———————————
interfaces : [‚Gi0/1’]
NEXT VLAN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

———————————
status : active
———————————
name : Management
———————————
vlan_id : 10
———————————
interfaces : []
NEXT VLAN !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


 

And yes, i know it’s still screen scraping. But kind of easier because you don’t have to do the regex and string manipulation yourself.

Next example was a bit more difficult because some templates don’t allow for headers. If something doesn’t work, look in your /home/.local/lib/python3.5/site-packages/ntc_templates/templates

In this case after „start’ we have just a record line, so in my show ip interface brief i removed the headers and just pasted the output.

cat cisco_ios_show_ip_interface_brief.textfsm
Value INTF (\S+)
Value IPADDR (\S+)
Value STATUS (up|down|administratively down)
Value PROTO (up|down)

Start
^${INTF}\s+${IPADDR}\s+\w+\s+\w+\s+${STATUS}\s+${PROTO} -> Record
# Capture time-stamp if vty line has command time-stamping turned on
^Load\s+for\s+
^Time\s+source\s+is


 

So here’s my final python script

templates.parse import parse_output

ship_output = (

"GigabitEthernet0/0/0 15.10.8.107 YES NVRAM up up\n"
"Loopback1255 111.21.186.11 YES NVRAM up up\n"
"Tunnel1251 111.21.173.11 YES NVRAM up up\n"
"Tunnel1255 111.21.187.11 YES NVRAM up up\n"
"Vlan1 192.168.8.11 YES NVRAM up up\n"


)
ship_parsed = parse_output(platform="cisco_ios", command="show ip interface brief", data=ship_output)

x = 0
while x <len(ship_parsed):
print()
print()
print('NEXT ONE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
print()
for key, value in ship_parsed[x].items():
print('---------------------------------')
print(key, ' : ', value)
x += 1

and the script output is…

NEXT ONE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---------------------------------
proto : up
---------------------------------
status : up
---------------------------------
intf : GigabitEthernet0/0/0
---------------------------------
ipaddr : 15.10.8.107


NEXT ONE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---------------------------------
proto : up
---------------------------------
status : up
---------------------------------
intf : Loopback1255
---------------------------------
ipaddr : 111.21.186.11


NEXT ONE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---------------------------------
proto : up
---------------------------------
status : up
---------------------------------
intf : Tunnel1251
---------------------------------
ipaddr : 111.21.173.11


NEXT ONE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---------------------------------
proto : up
---------------------------------
status : up
---------------------------------
intf : Tunnel1255
---------------------------------
ipaddr : 111.21.187.11


NEXT ONE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

---------------------------------
proto : up
---------------------------------
status : up
---------------------------------
intf : Vlan1
---------------------------------
ipaddr : 192.168.8.11
>>>
>>>

 

Netmiko redispatch with ssh bastion

Hello

In my network environment, to reach customer devices i need to go through a non-standard SSH proxy, where it’s not possible to do an SSH connection through the SSH connection to the proxy. I played with Netmiko last year but I didn’t know how to get through the ssh proxy such that i still could use Netmiko’s native set of methods once i connect to the final device. This turns out to be quite easy with the redispatch command.

In this script I can go through my devices and get the uptime from show version (words between „Uptime” up to „minutes”). This returns a list, so in order to create a nice output with the hostname and uptime, you need to insert the hostname at position 0 of the list (prepend).

from netmiko import ConnectHandler
import time
from netmiko import redispatch
import re

jumpserver={‚device_type’:’terminal_server’,’ip’:’11.1.1.1′,’username’:’username’,’password’:’cisco’,’port’:22,’global_delay_factor’:5,’session_log’: ‚output.txt’}

net_connect=ConnectHandler(**jumpserver)
net_connect.find_prompt()

net_connect.write_channel(„connect 172.16.0.1\n”)
time.sleep(2)
redispatch(net_connect, device_type=”cisco_ios”)
net_connect.enable
result = net_connect.send_command_timing(„show ver”)
endresult = re.findall(r’Uptime .*?minutes’, result)
endresult.insert(0,’DeviceR1′)
print(endresult)
net_connect.write_channel(„exit\n”)
time.sleep(1)

My own config generator and autoloader part 3 – Verification

Hello

In part 2 i uploaded the config using Telnet. Now, I don’t exactly trust telnet + my connection to the company install center is sometimes… not very trustworthy. Therefore, it would be good to verify the config against what was intended. To do that, i’ve extended the last upload script.

import pexpect
import os
import sys
from pathlib import Path

#now, the main method also includes a command that can be run, e.g. show run, creates a text file with the command output and copies it back to the windows folder. 

def createall(ip,port,consoleserver,argcommand):
   myarraypath = str(Path.home()).split('/')
   table = { 39 : None }
   myfinaluser = myarraypath[2].translate(table)
   print(myfinaluser)
   clearcommand = "truncate -s 0 c.txt"
   os.system(clearcommand)
   command = "tail --lines=+1 /mnt/c/Users/" + myfinaluser + "/Desktop/mycurrentscripts/test.txt >> /home/" + myfinaluser + "/c.txt"
   os.system(command)
   child = pexpect.spawn('telnet ' + ip + ' ' + port)
   argcommandnew = argcommand
   commandfile = open(argcommandnew, 'wb')
   child.timeout = 50
   child.delaybeforesend = 1.0
   myconsoleserver = consoleserver
   child.expect(consoleserver + ' login:')
   child.sendline('hereyourusername')
   child.expect('Password:')
   child.sendline('hereyourpassword')
   child.sendline()
   neverknow = child.expect(['#', '>'])
   if neverknow==1:
      child.sendline('en')
      child.expect('Password:')
      child.sendline('myenablepassword')
      child.expect('#')
   elif neverknow==0:
      child.sendline('configure terminal')
      child.expect('#')
      child.sendline('do terminal length 0')
      child.expect('#')
      child.logfile = commandfile
      child.sendline('do ' + argcommandnew)
      child.expect('(config)#')
   copycommand = 'cp ./' + commandfile + '/mnt/c/Users/' + myfinaluser + '/Desktop/mycurrentscripts/commandoutput'
   os.system(copycommand)
     # filename = 'c.txt'
     # with open(filename, encoding="utf8", errors='ignore') as file_object:
      #  lines = file_object.readlines()
       # for line in lines:
        #  line = line #+ "\015"
         # child.sendline(line)
#usage:
#python3 script.py 172.16.0.1 myconsoleserver 'show run'
if __name__ == "__main__":
  ip = sys.argv[1]
  port = sys.argv[2]
  consoleserver = sys.argv[3]
  argcommand = sys.argv[4]
  createall(ip, port, consoleserver, argcommand)


Now, you can use Notepad++ compare plugin to compare the two text files. At this point you will probably see that the two files are not identical due to peculiar formatting of the show run output. So then it’s time to go back to the template in the config python script and add extra spacing etc.

!
vrf definition 1
 rd 1:1
 !
 address-family ipv4
 exit-address-family
!
vrf definition 2
 description OtherVRF
 rd 2:1
 !
 address-family ipv4
 exit-address-family
!
vrf definition 3
 description VRF MGMT
 rd 3:1
 !
 address-family ipv4
 exit-address-family
!

Finally, don’t do”show run” but ”show run brief” to verify the config. This will remove the certificates from the output (less differences to look at in notepad). You will never get this 100% right, but in the end it looks pretty good.

 

My own config generator and autoloader part 2 – uploading the config

Hello

We finished part 1 where the config generator produced a test.txt file on the Window desktop. Now it’s time for another script to upload the config through a telnet connection. To do that, we need pexpect, and it’s not possible to install pexpect on windows. Fortunately, Windows 10 provides the windows subsystem for linux. I’ve installed Ubuntu using powershell.

Because the script doesn’t know the username, it needs to get the username folder from path.home. Once it has it, it reaches out to Windows, copies the test.txt config to its own c.txt file. Then it creates a telnet connection to the console server and uploads the config line by line.

import pexpect
import os
import sys
from pathlib import Path

def createall(ip,port,consoleserver):
#getting the username and copying the config
  myarraypath = str(Path.home()).split('/')
  table = { 39 : None }
  myfinaluser = myarraypath[2].translate(table)
  print(myfinaluser)

#if c.txt exists, contents should be deleted
  clearcommand = "truncate -s 0 c.txt"
  os.system(clearcommand)
  command = "tail --lines=+1 /mnt/c/Users/" + myfinaluser + "/Desktop/test.txt >> /home/" + myfinaluser + "/c.txt"
  os.system(command)
#spawning a connection
  child = pexpect.spawn('telnet ' + ip + ' ' + port)
  child.logfile = sys.stdout.buffer
  child.timeout = 14
  child.delaybeforesend = 1.0
  myconsoleserver = consoleserver
  child.expect(consoleserver + ' login:')
  child.sendline('yourlogin')
  child.expect('Password:')
  child.sendline('yourpassword')
  child.sendline()
#you just have to love my variable names
#you may see either of the prompts so 2 cases here
# if prompt is >, send an enable
  neverknow = child.expect(['#', '>'])
  if neverknow==1:
     child.sendline('en')
     child.expect('#')
#if prompt is #, upload the c.txt file line by line
  elif neverknow==0:
     child.sendline('configure terminal')
     child.expect('#')
     filename = 'c.txt' 
     with open(filename) as file_object:
       lines = file_object.readlines()
       for line in lines:
         line = line #+ "\015"
         child.sendline(line)

#this script can be run with the following command:
#python3 script.py 192.168.0.1 8002 myconsoleserver

if __name__ == "__main__":
  ip = sys.argv[1] 
  port = sys.argv[2]
  consoleserver = sys.argv[3]
  createall(ip, port, consoleserver)

My own config generator and autoloader part 1 – preparing the config

Hello again

It’s been a while since my last entry and i blame covid 🙂

Jokes aside, I used that 4 month break to do some thinking about where I want to be in a few years’ time. I kept learning python and watching how networks become more devops-oriented. The harsh reality is that most of network engineers will either lose their jobs or become programmers. There’s no denying that at this point.  Also, I personally feel that i’m a bit tired of good old network configuration (which is why i never did my ccie) and it’s time to make another step forward, just like 9 years ago when I joined the sonicwall support team. From now on my posts will concentrate more on how to automate operations rather than on operations per se.

Let’s start, then.

Part of what i do at work has to do with configuring new routers and sending them to client sites. I get a telnet connection through a console server to those routers, which isn’t ideal. Part 1 is coming up with the actual config, which is always a pain because you need to replace the config in a number of places. I’ve therefore come up with the following python script which:

  1. opens a GUI where you can put your config variables
  2. generates a config and saves the result to a test.txt file on the desktop
  3. archives the config as a <hostname>.txt file on the desktop
from networkconfgen import NetworkConfGen
import sys
import os

import PySimpleGUI as sg
import shutil
import socket
from tkinter import *
from tkinter import messagebox

#this creates the GUI layout 

sg.theme('DarkBlue1')

layout = [[sg.Text('My config generator')], 
[sg.Text('LAN IP', size=(21, 2)),sg.InputText('x.y.z.a'),sg.Text('subnet mask', size=(18, 2)),sg.InputText('255.255.255.248')], 
[sg.Text('WAN IP', size=(21, 2)),sg.InputText('a.s.d.f'),sg.Text('subnet mask', size=(12, 2)),sg.InputText('255.255.255.248')],
[sg.Text('hostname', size=(21, 2)),sg.InputText('testrouter')],
[sg.Text('VRRP IP', size=(21, 2)),sg.InputText('x.y.z.b')],
[sg.Text('WAN next hop', size=(21, 2)),sg.InputText()],
[sg.Text('Serial Number', size=(21, 2)),sg.InputText('BIGBROWNFOX')],
[sg.Text('tunnel1 IP', size=(21, 2)),sg.InputText('172.16.0.x'),sg.Text('subnet mask', size=(12, 2)),sg.InputText('255.255.255.0')],
[sg.Text('tunnel2 IP', size=(21, 2)),sg.InputText('172.16.1.x'),sg.Text('subnet mask', size=(12, 2)),sg.InputText('255.255.255.0')],
[sg.Text('loopback', size=(21, 2)),sg.InputText('172.16.2.x'),sg.Text('subnet mask', size=(12, 2)),sg.InputText('255.255.255.255')],
[sg.Text('network address of LAN', size=(21, 2)),sg.InputText('x.y.z.0'),sg.Text('subnet mask in slash format', size=(12, 2)),sg.InputText('/29')],
[sg.OK()]]

window = sg.Window('Window Title', layout) 
event, values = window.read()

#this reads the variables from the array generated by the GUI. 
lanip = values[0] 
lanipsubnetmask = values [1] 
wanip = values[2]
wanipsubnetmask = values [3]
hostname = values[4]
virtlanip = values[5]
nexthop = values[6]
serial = values[7]
tunnel1 = values[8]
tunnel1subnetmask = values[9]
tunnel2 = values[10]
tunnel2subnetmask = values[11]
loopback = values[12]
loopbacksubnetmask = values[13]
networklan = values[14]
networklansubnetmask = values[15]

#this checks if values in all fields are valid IP addresses

try:
socket.inet_aton(lanip)
socket.inet_aton(lanipsubnetmask)
socket.inet_aton(wanip)
socket.inet_aton(wanipsubnetmask)
socket.inet_aton(virtlanip)
socket.inet_aton(tunnel1)
socket.inet_aton(tunnel2)
socket.inet_aton(loopback)
socket.inet_aton(networklan)
# legal
except socket.error:
messagebox.showerror(title="OH BLIMEY", message="ADDRESSING MISTAKE")


window.close()

#this creates a confgen object

confgen = NetworkConfGen()

template = """

#here put any configuration you need with variables in the double brackets, example:
hostname {{hostname}}

interface Gi0/0
ip address {{WANIP}} {{WANIPSUNETMASK}}
"""
parameters = {
"hostname": hostname, 
"WANIP": wanip,
"WANIPSUBNETMASK": wanipsubnetmask,
"REALLANIP": lanip,
"REALLANIPSUBNETMASK": lanipsubnetmask,
"VIRTLANIP": virtlanip,
"NEXTHOPWANIP": nexthop,
"SERIAL": serial,
"TUNNEL1IP": tunnel1,
"TUNNEL1IPSUBNETMASK": tunnel1subnetmask,
"TUNNEL2IP": tunnel2,
"TUNNEL2SUBNETMASK": tunnel2subnetmask,
"LOOPBACKIP": loopback,
"LOOPBACKIPSUBNETMASK": loopbacksubnetmask,
"NETWORKLAN": networklan,
"NETWORKLANSUBNETMASK": networklansubnetmask
}
result = confgen.render_from_string(
template_content=template, 
parameters=parameters
)
if not result.render_error:
sys.stdout = open("test.txt", "w")
print(result.template_result)
sys.stdout.close()


else: 
print("Something went wrong: %s" % result.error_text)

oldname = 'test.txt'
shutil.copyfile(oldname,hostname)

SSH keys lost after reload on 16.9.2

Hello

I’m currently taking part in a project where we send out new routers to remote locations and on a number of occasions we had a problem where i couldn’t connect to my preconfigured router via ssh. I thought i was going crazy because this happened randomly and every time i had to console in to the router with the assistance of some onsite technician, which is always a hassle. And today i’ve found the confirmation in CSCvm54595: SSH keys can go missing if you write the config with do wr. Or you can upgrade to 16.9.3+.

I am not going mad after all. Cisco, this was not your finest (regression testing) hour.

What i did as a workaround…

event manager applet ssh_key_regenerate authorization bypass
event syslog occurs 1 pattern „SYS-5-RESTART” maxrun 90
action 1.0 cli command „enable”
action 1.1 cli command „conf t”
action 1.2 cli command „crypto key zeroize rsa MYSSHKEYS.server”
action 1.3 cli command „crypto key generate rsa general-keys label MYSSHKEYS modulus 4096”