📄 ethernet.tcl
字号:
switch -- $type {
0 { append icmpv4_msg "network" }
1 { append icmpv4_msg "host" }
2 { append icmpv4_msg "tos & network" }
3 { append icmpv4_msg "tos & host" }
default { append icmpv4_msg "unknown" }
}
set error 1
}
8 {
append icmpv4_msg "ping request"
if { [string length $packet] >= 8 } {
binary scan $packet {iss} junk id seq
append icmpv4_msg [format " id %u, seq %u" [expr $id & 0x0FFFF] [expr $seq & 0x0FFFF]]
set data 1
set packet [string range $packet 8 end]
}
}
9 {
append icmpv4_msg "router advertisement"
}
10 {
append icmpv4_msg "router solicitation"
}
11 {
append icmpv4_msg "time exceeded/"
switch -- $type {
0 { append icmpv4_msg "transit" }
1 { append icmpv4_msg "reassembly" }
default { append icmpv4_msg "unknown" }
}
set error 1
}
12 {
append icmpv4_msg "parameter problem/"
switch -- $type {
0 { append icmpv4_msg "IP header bad" }
1 { append icmpv4_msg "required option missing" }
default { append icmpv4_msg "unknown" }
}
set error 1
}
13 {
append icmpv4_msg "timestamp request"
}
14 {
append icmpv4_msg "timestamp reply"
}
15 {
append icmpv4_msg "information request"
}
16 {
append icmpv4_msg "information reply"
}
17 {
append icmpv4_msg "address mask request"
}
18 {
append icmpv4_msg "address mask reply"
}
default {
append icmpv4_msg "unknown"
}
}
if { $error && ([string length $packet] >= 36) } {
# The ICMP message contains an IP header and hopefully the TCP or UDP ports as well
# Only deal with the simple cases.
binary scan $packet {iiccSiccSIISS} icmp_junk1 icmp_junk2 ip_lenver ip_junk1 ip_junk2 ip_junk3 ip_junk4 ip_protocol ip_junk5 \
ip_source ip_dest ip_source_port ip_dest_port
if { (5 == ($ip_lenver & 0x0F)) && ((6 == $ip_protocol) || (17 == $ip_protocol)) } {
if { 6 == $ip_protocol } {
append icmpv4_msg ", tcp"
} else {
append icmpv4_msg ", udp"
}
append icmpv4_msg " >[ethernet::inet_ipv4_ntoa $ip_dest]:$ip_dest_port <[ethernet::inet_ipv4_ntoa $ip_source]:$ip_source_port"
}
}
append icmpv4_msg "\n"
synth::output $icmpv4_msg "eth_icmpv4"
# Only some of the requests contain additional data that should be displayed
if { !$data } {
return
}
} elseif { 58 == $ip_protocol } {
# ipv6 ICMP
if { [string length $packet] < 4 } {
return
}
binary scan $packet {ccS} code type checksum
set icmpv6_msg "$device $direction: ICMPv6 "
set error 0
set data 0
switch -- $code {
1 {
append icmpv6_msg "unreachable/"
switch -- $type {
0 { append icmpv6_msg "no route" }
1 { append icmpv6_msg "prohibited" }
2 { append icmpv6_msg "not a neighbour" }
3 { append icmpv6_msg "any other reason" }
4 { append icmpv6_msg "UDP port unreachable" }
default { append icmpv6_msg "unknown" }
}
set error 1
}
2 {
append icmpv6_msg "packet too big"
set error 1
}
3 {
append icmpv6_msg "time exceeded/"
switch -- $type {
0 { append icmpv6_msg "hop limit" }
1 { append icmpv6_msg "fragment reassembly" }
default { append icmpv6_msg "unknown" }
}
set error 1
}
4 {
append icmpv6_msg "parameter problem"
switch -- $type {
0 { append icmpv6_msg "erroneous header" }
1 { append icmpv6_msg "unrecognized next header" }
2 { append icmpv6_msg "unrecognized option" }
default { append icmpv6_msg "unknown" }
}
set error 1
}
128 {
append icmpv6_msg "ping request"
# FIXME: is this the same format as for icmpv4?
}
129 {
append icmpv6_msg "ping reply"
# FIXME: is this the same format as for icmpv4?
}
130 {
append icmpv6_msg "group membership query"
}
131 {
append icmpv6_msg "group membership report"
}
132 {
append icmpv6_msg "group membership reduction"
}
133 {
append icmpv6_msg "router solicitation"
}
134 {
append icmpv6_msg "router advertisement"
}
135 {
append icmpv6_msg "neighbour solicitation"
}
136 {
append icmpv6_msg "neighbour advertisement"
}
137 {
append icmpv6_msg "redirect"
}
}
if { $error && ([string length $packet] >= 44) } {
# The ICMP message contains an IPv6 header and hopefully the TCP or UDP ports as well
binary scan $packet {isccH16H16SS} icmp_junk1 icmp_junk2 ip_protocol icmp_junk3 ip_source ip_dest ip_source_port ip_dest_port
if { 6 == $ip_protocol } {
append icmpv6_msg ", tcp"
} elseif { 17 == $ip_protocol } {
append icmpv6_msg ", udp"
}
append icmpv6_msg " >[ethernet::inet_ipv4_ntoa $ip_dest]:$ip_dest_port <[ethernet::inet_ipv6_ntoa $ip_source]:$ip_source_port"
}
append icmpv6_msg "\n"
synth::output $icmpv6_msg "eth_icmpv6"
if { !$data } {
return
}
} elseif { 6 == $ip_protocol } {
# TCP
if { [string length $packet] < 20 } {
return
}
binary scan $packet {SSIIccSSS} source_port dest_port seq ack hdrsize flags winsize checksum urg
set source_port [expr $source_port & 0x0FFFF]
set dest_port [expr $dest_port & 0x0FFFF]
set hdrsize [expr ($hdrsize >> 4) & 0x0F]
set winsize [expr $winsize & 0x0FFFF]
set urg [expr $urg & 0x0FFFF]
set tcp_msg "$device $direction tcp: "
append tcp_msg " >${dest_name}:${dest_port}"
if { [info exists ethernet::services($dest_port,udp)] } {
append tcp_msg "($ethernet::services($dest_port,udp))"
}
append tcp_msg "<${source_name}:$source_port"
if { [info exists ethernet::services($source_port,udp)] } {
append tcp_msg "($ethernet::services($source_port,udp))"
}
append tcp_msg ", "
if { $flags & 0x08 } {
append tcp_msg "PSH "
}
if { $flags & 0x04 } {
append tcp_msg "RST "
}
if { $flags & 0x02 } {
append tcp_msg "SYN "
}
if { $flags & 0x01 } {
append tcp_msg "FIN "
}
append tcp_msg [format "seq %u" $seq]
if { 0 != ($flags & 0x010) } {
append tcp_msg [format ", ACK %u" $ack]
}
append tcp_msg ", win $winsize"
if { 0 != ($flags & 0x020) } {
append tcp_msg ", URG $urg"
}
append tcp_msg "\n"
synth::output $tcp_msg "eth_tcp"
set packet [string range $packet [expr 4 * $hdrsize] end]
} elseif { 17 == $ip_protocol } {
# UDP
if { [string length $packet] < 8 } {
return
}
set udp_msg "$device $direction: udp "
binary scan $packet {SSSS} source_port dest_port len checksum
set source_port [expr $source_port & 0x0FFFF]
set dest_port [expr $dest_port & 0x0FFFF]
append udp_msg [format "%d bytes, " [expr $len & 0x0FFFF]]
append udp_msg " >${dest_name}:$dest_port"
if { [info exists ethernet::services($dest_port,udp)] } {
append udp_msg "($ethernet::services($dest_port,udp))"
}
append udp_msg "<${source_name}:$source_port"
if { [info exists ethernet::services($source_port,udp)] } {
append udp_msg "($ethernet::services($source_port,udp))"
}
append udp_msg "\n"
synth::output $udp_msg "eth_udp"
set packet [string range $packet 8 end]
} else {
# Unknown protocol, so no way of knowing where the data starts.
return
}
# At this point we may have a payload. This should be
# dumped in both hex and ascii. The code tries to preserve
# alignment.
if { [string length $packet] == 0 } {
return
}
set hexdata_msg "$device $direction: data [format_hex_data $packet]\n"
set asciidata_msg "$device $direction: data "
set len [string length $packet]
if { $len > $ethernet::max_show } {
set len $ethernet::max_show
}
for { set i 0 } { $i < $len } { incr i } {
set char [string index $packet $i]
if { "\r" == $char } {
append asciidata_msg "\\r"
} elseif { "\n" == $char } {
append asciidata_msg "\\n"
} elseif { "\t" == $char } {
append asciidata_msg "\\t"
} elseif { [string is print -strict $char] } {
append asciidata_msg " $char"
} else {
append asciidata_msg "??"
}
if { 3 == ($i % 4) } {
append asciidata_msg " "
}
}
append asciidata_msg "\n"
synth::output $hexdata_msg "eth_hexdata"
synth::output $asciidata_msg "eth_asciidata"
return
}
# A utility for handling the ethernet record button on the toolbar
proc logging_button_toggle { } {
if { $ethernet::logging_enabled } {
set ethernet::logging_enabled 0
.toolbar.ethernet_logging configure -relief flat
} else {
set ethernet::logging_enabled 1
.toolbar.ethernet_logging configure -relief sunken
}
}
# A dummy procedure for initialization. All of this could execute at
# the toplevel, but there are lots of locals.
proc filters_initialize { } {
ethernet::read_services
ethernet::read_protocols
ethernet::read_hosts
# Add a button on the toolbar for enabling/disabling logging.
# Also add an entry to the help menu
if { $synth::flag_gui } {
button .toolbar.ethernet_logging -image $ethernet::image_netrecord -borderwidth 2 -relief flat -command ethernet::logging_button_toggle
pack .toolbar.ethernet_logging -side left -padx 2
synth::register_balloon_help .toolbar.ethernet_logging "Record ethernet traffic"
if { [synth::tdf_has_option "ethernet" "logging"] } {
set ethernet::logging_enabled [synth::tdf_get_option "ethernet" "logging"]
} else {
# Default to logging ethernet traffic. This may not be the right thing to do
# because users may see too much output by default, but it is easy enough
# to disable.
set ethernet::logging_enabled 1
}
if { $ethernet::logging_enabled } {
.toolbar.ethernet_logging configure -relief sunken
}
set ethernet_help [file join $synth::device_src_dir "doc" "devs-eth-synth-ecosynth.html"]
if { ![file readable $ethernet_help] } {
synth::report_warning "Failed to locate synthetic ethernet documentation $ethernet_help\n \
Help->Ethernet target menu option disabled.\n"
set ethernet_help ""
}
if { "" == $ethernet_help } {
.menubar.help add command -label "Ethernet" -state disabled
} else {
.menubar.help add command -label "Ethernet" -command [list synth::handle_help "file://$ethernet_help"]
}
}
if { [synth::tdf_has_option "ethernet" "max_show"] } {
set ethernet::max_show [synth::tdf_get_option "ethernet" "max_show"]
if { ! [string is integer -strict $ethernet::max_show] } {
synth::report_error "Ethernet device, invalid value in target definition file $synth::target_definition\n \
Entry max_show should be a simple integer, not $ethernet::max_show\n"
set ethernet::init_ok 0
}
}
# Filters. First, perform some validation.
set known_filters [list "ether" "arp" "ipv4" "ipv6" "icmpv4" "icmpv6" "udp" "tcp" "hexdata" "asciidata"]
set tdf_filters [synth::tdf_get_options "ethernet" "filter"]
array set filter_options [list]
foreach filter $tdf_filters {
if { 0 == [llength $filter] } {
synth::report_error "Ethernet device, invalid value in target definition file $synth::target_definition\n \
Option \"filter\" requires the name of a known filters.\n"
set ethernet::init_ok 0
continue
}
set name [lindex $filter 0]
if { [info exists filter_options($name)] } {
synth::report_error "Ethernet device, invalid value in target definition file $synth::target_definition\n \
\"filter $name\" should be defined only once.\n"
set ethernet::init_ok 0
continue
}
if { -1 == [lsearch -exact $known_filters $name] } {
synth::report_error "Ethernet device, invalid value in target definition file $synth::target_definition\n \
Unknown filter \"$name\".\n \
Known filters are $known_filters\n"
set ethernet::init_ok 0
continue
}
set filter_options($name) [lrange $filter 1 end]
}
# We now know about all the filter entries in the target definition file.
# Time to create the filters themselves, provided we are running in GUI mode.
if { $synth::flag_gui } {
foreach filter $known_filters {
if { ! [info exists filter_options($filter)] } {
synth::filter_add "eth_$filter" -text "ethernet $filter"
} else {
array set parsed_options [list]
set message ""
if { ![synth::filter_parse_options $filter_options($filter) parsed_options message] } {
synth::report_error \
"Invalid entry in target definition file $synth::target_definition\n \
Ethernet filter $filter\n $message"
set ethernet::init_ok 0
} else {
set parsed_options("-text") "ethernet $filter"
synth::filter_add_parsed "eth_$filter" parsed_options
}
}
}
}
}
ethernet::filters_initialize
}
return ethernet::instantiate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -