Overview | Index by: file name |
procedure name |
procedure call |
annotation
tools-1.0.tm
(annotations | original source)
#
# Copyright (C) 2010 Alexandros Stergiakis <alsterg@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#//#
# The "tools" module provides commands to aid network and host troubleshooting.
#
# @todo Interructive version of all commands. Currently only 'Traceroute', 'MailSend' and 'MailRecv' have interructive versions.
#//#
module require base 1.0
module require interface 1.0
module provide tools 1.0
namespace eval ::module::tools {
namespace import ::helper::* ::module::api::* \
::email::* ::module::interface::dlist_interfaces
proc description {} {
return "Troubleshooting tools and other aids"
}
proc version {} {
}
proc check {} {
foreach feature [list \
CONFIG_NSLOOKUP \
CONFIG_PING \
CONFIG_TRACEROUTE \
CONFIG_TELNET] {
if {! [::helper::busybox_has $feature]} { ;# Can return error.
error "Busybox doesn't have support for $feature."
}
}
}
proc reset {} {
}
proc constructor {} {
log::Info "Loading \"tools\" module: [description]"
check
reset
# Finally load Command Specs
sysconf loadspecs "modules/tools/tools.specs"
}
proc destructor {} {
# First unload Command Specs
sysconf remove "tools"
reset
}
################
# Handlers
################
# @interactive
command Telnet {cmdline argstart sid out no arguments args} {
if {[dict exists $arguments PORT]} {
set port [dict get $arguments PORT]
if {! [isipport $port]} {
ferror "illegal port number" [getpos PORT]
}
} else { set port {} }
if {[dict exists $arguments USER]} {
set user "-l [dict get $arguments USER]"
} else { set user {} }
set host [dict get $arguments HOST]
if {! [ishostname $host] && ! [isip $host]} {
ferror "illegal IP address or hostname" [getpos HOST]
}
ptyexec telnet {*}$user $host {*}$port
return
}
command Ping {cmdline argstart sid out no arguments args} {
if {[dict exists $arguments SIZE]} {
set size [dict get $arguments SIZE]
# IP header (20 bytes) + ICMP header (8 bytes) + payload
if {! [string is integer $size] || ! (0 <= $size <= 65000)} { ;# Somewhat less, to be on the safe side. ( @magic-number )
ferror "illegal payload size" [getpos SIZE]
}
set size "-s $size"
} else { set size {} } ;# 56 bytes.
if {[dict exists $arguments COUNT]} {
set count [dict get $arguments COUNT]
if {! [string is integer $count] || ! (1 <= $count <= 1000000)} { ;# We have to pick some upper bound. ( @magic-number )
ferror "illegal number" [getpos COUNT]
}
set count "-c $count"
} else { set count {} } ;# For ever.
if {[dict exists $arguments IPADDR]} {
set src [dict get $arguments IPADDR]
if {! [isip $src]} {
ferror "illegal IP address" [getpos IPADDR]
}
set src "-I $src"
} elseif {[dict exists $arguments INTERFACE]} {
set src "-I [dict get $arguments INTERFACE]"
} else { set src {} } ;# We don't care which IP address will use as source.
set host [dict get $arguments HOST]
if {! [ishostname $host] && ! [isip $host]} {
ferror "illegal IP address or hostname" [getpos HOST]
}
ptyexec -root -- ping {*}$size {*}$count {*}$src $host
return
}
command Nslookup {cmdline argstart sid out no arguments args} {
set host [dict get $arguments HOST]
if {! [ishostname $host] && ! [isip $host]} {
ferror "illegal IP address or hostname" [getpos HOST]
}
if {[dict exists $arguments SERVER]} {
set server [dict get $arguments SERVER]
if {! [isip $server]} {
ferror "illegal ip address" [getpos SERVER]
}
} else { set server {} }
ptyexec -- nslookup $host {*}$server
return
}
# @interactive
command Traceroute {cmdline argstart sid out no arguments args} {
Global DNS_LOOKUPS
if {[dict exists $arguments HOST]} {
set host [dict get $arguments HOST]
if {! [ishostname $host] && ! [isip $host]} {
ferror "illegal IP address or hostname" [getpos HOST]
}
ptyexec -root -- traceroute -v {*}[? !$DNS_LOOKUPS "-n"] $host
return
}
# Ask the user for details:
# @magic-number : Various magic numbers follow:
set target [ask -eval {expr {[isip %%] || [ishostname %%]}} "Target IP address or hostname: "]
set payload [ask -type integer -default 56 -min 0 -max 65000 "Size of data payload: "]
set switches {}
lappend switches [ask -switch "-s" -check isip -default {} -noswitch "IP address to use as the source address: "]
lappend switches [ask -switch "-i" -list [dlist_interfaces] -default {} -noswitch "Interface to use to send probe packets: "]
set icmp [ask -switch "-I" -type boolean -default n "Use ICMP ECHO instead of UDP datagrams: "]
if {$icmp ne "-I"} {
set port [ask -switch "-p" -check isipport -default 33434 "Base UDP port number used in probes: "]
}
lappend switches $icmp
lappend switches [ask -switch "-n" -neg -type boolean -default y "Display hostnames instead of IP addresses: "]
lappend switches [ask -switch "-f" -type integer -default 1 -min 1 -max 256 "First Time to Live: "]
lappend switches [ask -switch "-m" -type integer -default 100 -min 1 -max 256 "Maximum Time to Live: "]
lappend switches [ask -switch "-q" -type integer -default 3 -min 1 -max 10 "Number of probes per TTL: "]
lappend switches [ask -switch "-w" -type integer -default 3 -min 1 -max 100 "Time in seconds to wait for a response: "]
lappend switches [ask -switch "-z" -type integer -default 0 -noswitch -min 0 -max 100000 "Time in milliseconds to wait between consequtive TTLs: "]
lappend switches [ask -switch "-t" -type integer -default 0 -min 0 -max 256 "Type-of-service in probe packets: "]
lappend switches [ask -switch "-F" -type boolean -default n "Set the don't fragment bit: "]
lappend switches [ask -switch "-l" -type boolean -default n "Show TTL of reply packets: "]
#lappend switches [ask -switch "-r" -type boolean -default n "Skip routing table: "]
#lappend switches [ask -switch "-g" -default {} "Loose source route gateway (max 8 IPs): "]
sputs "" ;# newline
set switches [concat {*}$switches]
ptyexec -root -- traceroute -v {*}$switches $target $payload
return
}
# @block
# @interactive
command MailSend {cmdline argstart sid out no arguments args} {
Global TIMEOUT
if {[dict exists $arguments SERVER]} {
# Information is provided on the command line.
set server [dict get $arguments SERVER]
if {! ([isip $server] || [ishostname $server])} {
ferror "Not a valid hostname or IP address" [getpos SERVER]
}
set port [getval PORT 25]
if {! [isipport $port]} {
ferror "Not a valid port number" [getpos PORT]
}
set username [getval USERNAME {}]
set password [getval PASSWORD {}]
set from [dict get $arguments FROM]
if {! [isemail $from]} {
ferror "Not a valid email address" [getpos FROM]
}
set to [dict get $arguments TO]
if {! [isemail $to]} {
ferror "Not a valid email address" [getpos TO]
}
set subject [dict get $arguments SUBJECT]
set body [dict get $arguments MESSAGE]
} else {
# Ask for the necessary information.
set server [ask -eval {expr {[isip %%] || [ishostname %%]}} "Hostname or IP address of SMTP Server: "]
set port [ask -check isipport -default 25 "Port number the SMTP Server is listening at: "]
if {[ask -type boolean -default n "Authenticate on the Server: "]} {
set username [ask "Username: "]
set password [ask -noecho "Password: "]
} else {
set username {}
set password {}
}
set from [ask -check isemail "From: "]
set to [ask -check isemail "To: "]
set subject [ask -length 100 "Subject: "]
set body [ask -end "\n.\n" "Body: (end with a single \".\" on a line of its own)\n"]
sputs "\nSending e-mail..."
}
timeout $TIMEOUT {
::email::smtpSend $from $to $subject $body $server $port $username $password
}
# If we reach here, it means no error occured before. Email was sent.
puts "Email sent successfully"
return
}
# @block
# @interactive
command MailRead {cmdline argstart sid out no arguments args} {
Global TIMEOUT
Session $sid COLUMNS
if {[dict exists $arguments SERVER]} {
set server [dict get $arguments SERVER]
if {! ([isip $server] || [ishostname $server])} {
ferror "Not a valid hostname or IP address" [getpos SERVER]
}
set username [dict get $arguments USERNAME]
set password [dict get $arguments PASSWORD]
set port [getval PORT 110]
if {! [isipport $port]} {
ferror "Not a valid port number" [getpos PORT]
}
timeout $TIMEOUT {
set popsock [::email::popOpen $server $port $username $password]
set messages [::email::popRead $popsock]
lassign [::email::popCount $popsock] msgcount msgsize
::email::popClose $popsock
}
puts "\nYou have $msgcount new emails, totaling $msgsize bytes\n"
foreach msg $messages {
puts [string repeat _ $COLUMNS]
puts [lindex $msg 0]
}
return
}
# else:
set server [ask -eval {expr {[isip %%] || [ishostname %%]}} "Hostname or IP address of POP3 Server: "]
set port [ask -check isipport -default 110 "Port number the POP3 Server is listening at: "]
set username [ask "Username: "]
set password [ask -noecho "Password: "]
sputs -nonewline "\nConnecting..."
timeout $TIMEOUT {
set popsock [::email::popOpen $server $port $username $password]
}
sputs "OK"
sputs -nonewline "Reading Inbox..."
timeout $TIMEOUT {
set messages [::email::popRead $popsock]
}
sputs "OK"
timeout $TIMEOUT {
lassign [::email::popCount $popsock] msgcount msgsize
}
sputs "\nYou have $msgcount new emails, totaling $msgsize bytes\n"
if {$msgcount > 0} {
sputs "Press Enter to continue."
ask -length 0 -default {} -hidedef ""
}
for {set i 0} {$i < $msgcount} {incr i} {
sputs [string repeat _ $COLUMNS]
sputs [lindex $messages $i 0]\n
set choice [ask -list {n p d a} "Next (n) - Print again (p) - Delete (d) - Abort (a): "]
switch -exact -- $choice {
"n" { continue }
"p" { incr i -1 }
"d" {
timeout $TIMEOUT {
::email::popDelete $popsock $i+1
}
}
"a" { break }
}
}
sputs -nonewline "Closing mailbox..."
timeout $TIMEOUT {
::email::popClose $popsock
}
sputs "OK"
return
}
# @block
command MailCheck {cmdline argstart sid out no arguments args} {
Global TIMEOUT
set server [dict get $arguments SERVER]
if {! ([isip $server] || [ishostname $server])} {
ferror "not a valid hostname or IP address" [getpos SERVER]
}
set username [dict get $arguments USERNAME]
set password [dict get $arguments PASSWORD]
set port [getval PORT 110]
timeout $TIMEOUT {
set popsock [::email::popOpen $server $port $username $password]
lassign [::email::popCount $popsock] msgcount msgsize
::email::popClose $popsock
}
puts "You have $msgcount new emails, totaling $msgsize bytes"
return
}
} ;# End of Namespace
Overview | Index by: file name |
procedure name |
procedure call |
annotation
File generated 2010-03-13 at 22:28.