Code

YOU CAN COPY/PASTE AND USE THE BELOW CODE

# Copyright © 2011 Edinburgh Napier University
# All rights reserved.
#
# by: Antonio Gil, MSc Computer Networking
# title: B-header: Simplified Cisco IOS protocol analyzer
#
# name: bheader1.tcl
# desc: This script can be executed from a TFTP server or from the router's
# flash memory.

###########################################################
################# START #######################
###########################################################

# This command prevents verbose debugging output showing on the console (default)

config t
no logging console

#The previous command should suffice for the next task. However, the following
#ensures logging to buffer memory and enough memory

logging buffered 500000
exit

#The variable "$interfaces" will collect all the interface information.

set interfaces ""
set user_input ""


proc show_version {} {

set output [exec "show ver"]
set firstposition [string first "Cisco IOS" $output]

if {$firstposition > -1} {
set lastposition [string first "\n" $output $firstposition]
set version [string range $output $firstposition $lastposition]

puts ""
puts "\033\[33m Running $version \033\[0m"

}

}

proc printInterface {dataName} {
upvar $dataName data
global lineFormat paramActive paramConfig interfaces
if {! [array exists data]} { return }
if {$paramActive != 0} { if {! [string equal $data(IFSTAT) "up"]} { return } }
if {$paramConfig != 0} { if {[string equal $data(IPADDR) "no address"]} { return } }
if {[string equal $data(IFSTAT) "up"]} { set data(IFSTAT) "\033\[32m up \033\[0m"}
append interfaces [format $lineFormat "" $data(IFNAME) $data(IPADDR) $data(IPMTU) $data(IFSTAT)\n]
}

proc usage {} { puts {Syntax: ipconfig [active|configured|address]} }


proc parseParams {} {
global paramActive paramConfig paramAddress argv

set paramActive 0
set paramConfig 0
set paramAddress 0

foreach par $argv {
switch $par {
active { set paramActive 1 }
configured { set paramConfig 1 }
address { set paramAddress 1 }
help { usage; return 1; }
default { usage; return 1; }
}
}
return 0;
}



if {[parseParams] == 1} {return}
set lineFormat "\033\[0m %-20s %-20s %-20s %-10s %s \n"
exec "terminal international"
puts "\033\[2J"
puts "\033\[0;0H"

append interfaces [format $lineFormat {} {Interface} {IP Address} {MTU} {State} ]
append interfaces " \033\[0m \033\[33m=========================================================================\033\[0m \033\[33m \n\n"


exec {terminal ip netmask-format bit-count}
set cmdtext [exec {show ip interface}]
##set paramActive [string equal [lindex $argv 0] "active"]
foreach line [split $cmdtext "\n"] {
if {[regexp -nocase {^(\S+) is (.*), line protocol is (\S+)} $line ignore ifname ifstat iflstat]} {
printInterface ifdata
set ifdata(IFNAME) $ifname
set ifdata(IPADDR) "no address"
set ifdata(IPMTU) ""
set ifdata(IFSTAT) $ifstat
if {[string equal $ifstat "up"]} {
if {![string equal $iflstat "up"]} { set ifdata(IFSTAT) "$ifstat/$iflstat" }
}
regsub -all {administratively} $ifdata(IFSTAT) "admin" ifdata(IFSTAT)
} elseif {[regexp -nocase {internet address is ([0-9.]+/[0-9]+)} $line ignore ipaddr]} {

set ifdata(IPADDR) $ipaddr
} elseif {[regexp -nocase {Using address of (\S+)\s+\(([0-9.]+)\)} $line ignore ipif ipaddr]} {
set ifdata(IPADDR) $ipif
if {$paramAddress != 0} { set ifdata(IPADDR) "$ipaddr (U)" }
} elseif {[regexp -nocase {MTU is ([0-9]+)} $line ignore ipmtu]} {
set ifdata(IPMTU) $ipmtu
}
}

if {[array exists ifdata]} { printInterface ifdata }
exec {terminal no ip netmask-format bit-count}




############################## Start & Stop capture #############################################


proc start_capture {} {

global user_input

#and this command starts the capture of packets on the buffer
exec debug ip packet dump
exec "terminal international"

puts "\033\[2J\033\[H\033\[1;31m WELCOME TO b-HEADER !!! The simplified router analyzer\033\[0m"
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts ""
puts ""
puts "capturing packets..."
puts ""
puts ""
puts "Press '3' to stop capture"
puts "Press 'p' to create a pcap file"
gets stdin input
if {$input == "3"} {
stop_capture
} elseif {$input == "p"} {

exec "no debug all"
set capture [exec "show loggin"]
# buffer content gets cleared
typeahead "y"
exec "clear logging"

set output [hexdump2pcap $capture]
puts stdout $output

puts "Press 'b' to go back to Main Menu"
gets stdin input
if {$input == "b"} {
main_menu
}
}

}

proc stop_capture {} {

#pressing "3" will fire the following command to stop the capture
no debug all

#now it is important to clear the varible to which the whole buffer contents will be dumped
set capture ""
set header_part1 ""
set header_part2 ""
set packet_no null

# buffer content gets collected and stored in the variable 'capture'
set capture [exec "show loggin"]

# buffer content gets cleared
typeahead "y"
exec "clear logging"
capture_analyzer $capture

}

################################ Conversion of Hex dump into PCAP #############################


proc hexdump2pcap {capture} {


set i 0
set line1 ""
set line2 ""

#The hex dump is parsed line by line.
#Only the lines starting with an offset followed by four groups of 8-character strings will be examined.
foreach line [split $capture "\n"] {
if {[regexp -nocase {^(\S+:) (........) (........) (........) (........)}\
$line ignore mem_add first second third fourth]} {

#Offset is trimmed off and discarded. Then the four strings are put together in a single line
#and stored in the 'line2' variable.
set line1 "$first$second$third$fourth"
append line2 $line1
#When the line does not match the above pattern it indicates the end of a packet.
#At this point the packet is processed for printing with the new format.
} elseif {$line != 1} {


set t2pcaplist ""

set rng [string length $line2]


for { set e 1 } { $e < $rng } { incr e 2 } {
set i [expr $e - 1]
set byte [string range $line2 $i $e]

if {$byte == " "} {
set byte "00"
}

lappend t2pcaplist $byte
}

if {[lindex $t2pcaplist 8] == "45"} {

set t2pcaplist45 [linsert $t2pcaplist 7 00 00 00 00 00 08]
set t2pcaprange [llength $t2pcaplist45]


set e 15
set o 0
for {set init 0} { $init < $t2pcaprange} { incr init 16} {
set t2pcapline [lrange $t2pcaplist45 $init $e]
set pcap_offset [format %#04s $o]
set finalline "$pcap_offset $t2pcapline"


puts $finalline

set e [expr $e + 16]
incr o 10
}
} elseif {[lindex $t2pcaplist 10 ] == "01"} {

set t2pcaplist0100 [lrange $t2pcaplist 10 end]
set t2pcaprange [llength $t2pcaplist0100]


set e 15
set o 0

for {set init 0} { $init < $t2pcaprange} { incr init 16} {
set t2pcapline [lrange $t2pcaplist0100 $init $e]
set pcap_offset [format %#04s $o]
set finalline "$pcap_offset $t2pcapline"


puts $finalline


set e [expr $e + 16]
incr o 10
}

}



puts " "

set line2 ""
set t2pcaplist ""
set t2pcaplist45 ""
}


}

}



proc conditional_capture {selected_interface} {

exec "debug interface $selected_interface"

exec "terminal international"

puts "\033\[2J\033\[H\033\[1;31m WELCOME TO b-HEADER !!! The simplified router analyzer\033\[0m"
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts ""
puts ""
puts "capturing packets..."
puts ""
puts ""
puts "Press '3' to stop capture"

gets stdin input
if {$input == "3"} {stop_capture}

}



#==================================================================================
#Once the above procedure has finished parsing, all the information about
#all the active interfaces and their status is stored in the "$interfaces" #variable.
#==================================================================================

proc show_interfaces {} {
exec "terminal international"
puts "\033\[2J\033\[H\033\[1;31m WELCOME TO b-HEADER !!! The simplified router analyzer\033\[0m"
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts ""
puts ""

global interfaces
puts $interfaces

#And the submenu is displayed below

puts " You are presented with the choice of capturing packets from one or more interfaces. "
puts " For capturing on your chosen interface please enter interface like in the following "
puts " example: "
puts ""
puts { Ethernet0/1 }
puts ""
puts ""
puts ""
puts ""
puts ""
puts ""
puts ""
puts ""
puts {p - promiscuous debugging}
puts {b - back to main menu}
puts ""

#User input is collected in "$interface_input"
set interface_input [gets stdin]

#Input switch
switch -glob $interface_input {
"b" {main_menu}

"p" {start_capture}
default {conditional_capture $interface_input}
}

}

################################### Packet Analysis ############################################


proc capture_analyzer { capture } {

#Clear screen
exec "terminal international"
puts "\033\[2J\033\[H\033\[1;31m WELCOME TO b-HEADER !!! The simplified router analyzer\033\[0m"
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts ""
puts ""

# Make a nice header with separators for the table
set w1 12
set w2 9
set w3 5
set w4 9
set w5 5
set w6 17
set w7 10
set w8 12
set w9 16
set sep +-[string repeat - $w1]-+-[string repeat - $w2]-+-[string repeat - $w3]-+-[string repeat - $w4]-+-[string repeat - $w5]-+-[string repeat - $w6]-+-[string repeat - $w7]-+-[string repeat - $w8]-+-[string repeat - $w9]+
puts $sep
puts [format "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s|" $w1 "Ethertype" $w2 "H. Length" $w3 " TOS"\
$w4 "Total Len" $w5 " TTL" $w6 "Protocol Type" $w8 " Checksum" $w8 "Source Add" $w9 "Destination Add"]
puts $sep

#===================== THE LOOP FOR EACH PACKET ============================================

set packet_counter 0

foreach line [split $capture "\n"] {


if {[string first "0800 45" $line ] != -1} {

set clue "0800 45"
#0x800 means IP, 4 means IPv4 and 5 the header lengh in bytes
#Therefore we are pretty sure this is the beginning of an IP packet header
#the range of the first line of the header is 21 bytes after the beginning
#while {[string match {**** 45} $capture] != -1}
set begin [string first $clue $capture]
set end_of_first_line [expr [string first $clue $capture] + 21]

#The packet header is processed in two parts. The first part is stored in the 'header_part1' variable.
set header_part1 [string range $capture $begin $end_of_first_line]

#Once the first line of the packet has been cut and stored, it has to be cleared for two reasons;

#first, to avoid a 'while' statement endless loop and second, to start parsing the next first line.
#The code "eats" one first line and then a second to form the two parts of the header. Anything
#preceding the next line is thus deleted, storing the remaining capture data in the 'capture' variable.

set capture [string range $capture $begin [string length $capture]]
set capture [string range $capture [expr [string first "\n" $capture] + 1] [string length $capture]]

# ----------HEADER PART 2------------------------------------


#The second part of the header is cut and stored in 'header_part2'.
set header_part2 [string range $capture [ expr [ string first ":" $capture] + 2] 44]


# ----------FINAL PACKET------------------------------------
#The two parts are put together and the final packet header is assembled and stored in 'packet'
set packet "$header_part1 $header_part2"

incr packet_counter
display $packet


}
}

puts "***************************************************************************************************************************"
puts "TOTAL PACKETS CAPTURED: $packet_counter"
puts ""
puts ""
puts "Press 'c' to start another capture"
puts "Press 'b' to go back to Main Menu"
puts ""
puts ""
puts ""
puts ""
puts ""
puts "Press 'q' to quit"
gets stdin input
switch -glob $input {
"b" {main_menu}
"c" {start_capture}
"q" {puts "Thank you for using b-header"
puts "by: Antonio Gil, MSc Computer Networking"
puts "Copyright (c) 2011 Edinburgh Napier University"
puts "All rights reserved"
}
default {puts "Please press the right key."}
}
}

########################################## Packet Display ############################################


proc display {packet} {

# Set up the column widths
set w1 12
set w2 9
set w3 5
set w4 9
set w5 5
set w6 17
set w7 11
set w8 12
set w9 16

#Packet dissection

set ethertype "0x800 (IPv4)"

set header_length [expr 0x[string range $packet 6 6]]
set tos [expr 0x[string range $packet 7 8]]
set total_length [expr 0x[string range $packet 9 12]]
set ttl [expr 0x[string range $packet 23 24]]
set protocol_type [string range $packet 25 26]
set header_checksum [expr 0x[string range $packet 27 30]]

#Conversion from hex to decimal of source and destination IP addresses
set src_ip1 [expr 0x[string range $packet 32 33]]
set src_ip2 [expr 0x[string range $packet 34 35]]
set src_ip3 [expr 0x[string range $packet 36 37]]
set src_ip4 [expr 0x[string range $packet 38 39]]

set source_address "$src_ip1.$src_ip2.$src_ip3.$src_ip4"


set des_ip1 [expr 0x[string range $packet 41 42]]
set des_ip2 [expr 0x[string range $packet 43 44]]
set des_ip3 [expr 0x[string range $packet 45 46]]
set des_ip4 [expr 0x[string range $packet 47 48]]

set destination_address "$des_ip1.$des_ip2.$des_ip3.$des_ip4"


if {$protocol_type == "01"} {
set protocol_type "01 (ICMP)"
puts [format "\033\[33m| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s|\033\[0m"\
$w1 $ethertype $w2 $header_length $w3 $tos $w4 $total_length $w5 $ttl $w6 $protocol_type $w7 $header_checksum $w8 $source_address $w9 $destination_address]
} elseif {$protocol_type == "11"} {
set protocol_type "06 (TCP)"
puts [format "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s|\033\[0m"\
$w1 $ethertype $w2 $header_length $w3 $tos $w4 $total_length $w5 $ttl $w6 $protocol_type $w7 $header_checksum $w8 $source_address $w9 $destination_address]
} elseif {$protocol_type == "11"} {
set protocol_type "11 (UDP)"
puts [format "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s|\033\[0m"\
$w1 $ethertype $w2 $header_length $w3 $tos $w4 $total_length $w5 $ttl $w6 $protocol_type $w7 $header_checksum $w8 $source_address $w9 $destination_address]
} elseif {$protocol_type == "58"} {
set protocol_type "88 (EIGRP)"
puts [format "\033\[36m| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s|\033\[0m"\
$w1 $ethertype $w2 $header_length $w3 $tos $w4 $total_length $w5 $ttl $w6 $protocol_type $w7 $header_checksum $w8 $source_address $w9 $destination_address]
} elseif {$protocol_type == "59"} {
set ospf_type [string range $packet 52 53]
switch -glob $ospf_type {
"01" {set protocol_type "89 (OSPF 1 Hello)"}
"02" {set protocol_type "89 (OSPF 2 DBD)"}
"03" {set protocol_type "89 (OSPF 3 LSR)"}
"04" {set protocol_type "89 (OSPF 4 LSU)"}
"05" {set protocol_type "89 (OSPF 5 LSAck)"}
default {set protocol_type "89 (OSPF)"}
}
puts [format "\033\[32m| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s|\033\[0m"\
$w1 $ethertype $w2 $header_length $w3 $tos $w4 $total_length $w5 $ttl $w6 $protocol_type $w7 $header_checksum $w8 $source_address $w9 $destination_address]
}

}









###################################### Main Menu ################################################




proc main_menu {} {
exec "terminal international"
puts "\033\[2J\033\[H\033\[1;31m WELCOME TO b-HEADER !!! The simplified router analyzer\033\[0m"
puts ""
puts ""
puts ""
puts ""
puts " _ _ "
puts { -/~/ / ~\ }
puts { || | | /\ ;\ }
puts { \\)\)\)/ ;;; }
puts { ///(())(__/~\ }
puts { (((__ ___\\ \ }
puts { )))--`. + (( ;,8 \ }
puts { ((\ | /)) .,88 `: ..,,;;;;,-: }
puts { )| ~-~ |(|(888; ..``'::::8888oo }
puts { |\ -===- /| \8;; ``:. oo.88 }
puts { |_~-___-~_| `-\. ` `o` }
puts " \033\[31m!!!@!@!\033\[0m `--_`._-__--_-__ \033\[31m"

puts { !!: :!! }
puts { :!: !:! }
puts { ___ _ :: :: _ }
puts " /\033\[33m __\033\[31m\\ | |__; ___; __ _ __| | ___ _ __ \033\[33m "
puts { /__\//_____| '_ \ / _ \/ _` |/ _` |/ _ \ '__| }
puts { / \/ \_____| | | | __/ (_| | (_| | __/ | }
puts { \_____/ |_| |_|\___|\__,_|\__,_|\___|_| }
puts { }
puts " \033\[32mBUFFER PACKET ANALYZER "
puts ""
puts " \033\[0m 1.Show & Select Interfaces "
puts " \033\[0m 2.Start Capture "
puts " \033\[0m 3.Stop Capture "
puts " \033\[0m 4.Show CPU History "
puts " \033\[0m 5.Help "
puts " \033\[0m 6.Disclaimer "puts { }
puts " \033\[0m ***\033\[36m Copyright (c) Antonio Gil 2011\033\[0m *** "
puts " \033\[31m+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+ \033\[0m "
puts { |E|d|i|n|b|u|r|g|h| |N|a|p|i|e|r| |U|n|i|v|e|r|s|i|t|y| }
puts " \033\[31m+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+\033\[0m "
puts ""
puts ""
puts { ***************************************************************************************************}
show_version
puts { ***************************************************************************************************}

main_menu_input

}

proc main_menu_input {} {
gets stdin input
switch -glob $input {
"1" {show_interfaces}
"2" {start_capture}
"3" {stop_capture}
"4" {cpu_history}
"5" {help}
"6" {disclaimer}

"q" {quit}
default {puts "Please press the right key."}
}
main_menu_input
}

################################### CPU ACTIVITY ############################################

proc cpu_history {} {
set cpu [exec "show processes cpu history"]
puts "\033\[32m $cpu \033\[0m"
puts "Press 'q' to quit"
gets stdin input
switch -glob $input {
"b" {main_menu}
"q" {quit}

default {puts "Please press the right key."}
}

}

############################# DISCLAIMER #################################################

proc disclaimer {} {

exec "terminal international"
puts "\033\[2J\033\[H\033\[1;31m WELCOME TO b-HEADER !!! The simplified router analyzer\033\[0m"
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts ""
puts " IMPORTANT "
puts ""
puts ""
puts " The developer of this program is NOT AFFILIATED with Cisco Inc."
puts ""
puts " This program is\033\[32m free\033\[0m. Therefore, if you paid for it, you were scammed!"
puts ""
puts ""
puts " ATTENTION:"
puts ""
puts " This program is distributed in the hope that it will be useful,"
puts " but WITHOUT ANY WARRANTY; without even the implied warranty of"
puts " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
puts ""
puts ""
puts " From the \033\[33m GNU General Public License\033\[0m , Version 2, June 1991:"
puts ""
puts " \033\[31m- NO WARRANTY -\033\[0m"
puts ""
puts " 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS"
puts " NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY"
puts " APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE"
puts " COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM"
puts " AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR"
puts " IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES"
puts " OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE"
puts " ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM"
puts " IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME"
puts " THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION."
puts ""
puts " 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO"
puts " IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO"
puts " MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE,"
puts " BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,"
puts " INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR"
puts " INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOS"
puts " OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED"
puts " BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE"
puts " WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY"
puts " HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES."
puts ""
puts ""
puts " Antonio Gil, Edinburgh Napier University."
puts ""
puts ""
puts ""
puts ""
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts "Press 'b' to go back to Main Menu"
puts "Press 'q' to quit"
gets stdin input
switch -glob $input {
"b" {main_menu}
"q" {quit}

default {puts "Please press the right key."}
}

}
############################################## QUIT PROGRAM ################################################

proc quit {} {
puts "Thank you for using b-header"
puts "by: Antonio Gil, MSc Computer Networking"
puts "Copyright (c) 2011 Edinburgh Napier University"
puts "All rights reserved"
exec "break"
}



############################################## HELP ######################################################



proc help {} {

exec "terminal international"
puts "\033\[2J\033\[H\033\[1;31m WELCOME TO b-HEADER !!! The simplified router analyzer\033\[0m"
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts ""
puts " WHAT IS B-header? "
puts ""
puts " B-header is a little program written in the Tcl scripting language"
puts " that takes advantage of the hex dumps stored in the buffer of Cisco "
puts " routers and presents the protocol headers like a protocol analyzer "
puts " would do."
puts ""
puts " \033\[32mOption 1\033\[0m displays the available interfaces and their states"
puts " \033\[32mOption 2\033\[0m starts debugging mode and network traffic will be stored in the buffer"
puts " \033\[32mOption 3\033\[0m offers two alternatives; '3'stops all debugging and displays packet headers"
puts " 'p'stops all debugging and displays a format for"
puts " processing in Wireshark's '\033\[33mtext2pcap\033\[0m' tool."
puts " "
puts " For questions, comments or suggestions please email: antoniogilcamacho@hotmail.com"
puts " "
puts " You can also visit antonio.gil.freeshell.org"
puts " "
puts " "
puts " Antonio Gil, Edinburgh Napier University."
puts ""
puts ""
puts ""
puts ""
puts {****************************************************************************************************}
puts {****************************************************************************************************}
puts "Press 'b' to go back to Main Menu"
puts "Press 'q' to quit"
gets stdin input
switch -glob $input {
"b" {main_menu}
"q" {quit}
default {puts "Please press the right key."}
}

}

main_menu