main.tcl at tip

File main.tcl from the latest check-in


#! /usr/bin/env tclsh

package require starkit
starkit::startup

lappend auto_path [file join $::starkit::topdir twapi]

package require twapi

# Determine platform to install driver for
## http://blogs.msdn.com/b/david.wang/archive/2006/03/26/howto-detect-process-bitness.aspx
if {[info exists ::env(PROCESSOR_ARCHITEW6432)]} {
	set arch $::env(PROCESSOR_ARCHITEW6432)
} else {
	if {[info exists ::env(PROCESSOR_ARCHITECTURE)]} {
		set arch $::env(PROCESSOR_ARCHITECTURE)
	} else {
		set arch "x86"
	}
}
switch -- [string tolower $arch] {
	"x86" {
		set bits "32"
	}
	default {
		set bits "64"
	}
}

# Determine temp directory
if {[info exists ::env(TEMP)]} {
	set tmpdir $::env(TEMP)
} elseif {[info exists ::env(TMPDIR)]} {
	set tmpdir $::env(TMPDIR)
} else {
	if {$tcl_platform(platform) == "windows"} {
		set tmpdir {C:/TEMP}
	} else {
		set tmpdir /tmp
	}
}

# Determine interface to lookup
set dest_parm_idx [lsearch -exact $argv "-i"]
if {$dest_parm_idx != -1} {
	incr dest_parm_idx

	set dest_chk [lindex $argv $dest_parm_idx]
	if {[string match "*.*.*.*" $dest_chk] || [string match "*:*:*" $dest_chk]} {
		set dest $dest_chk

		## Determine the index to specified destination
		set iface_idx 1
		catch {
			set iface_idx [::twapi::get_outgoing_interface $dest]
		}
		if {$iface_idx == ""} {
			set iface_idx 1
		}

		## Determine the NPF name for the adapter found above
		set iface_adapter [lindex [::twapi::get_netif_info $iface_idx -adaptername] 1]
		set iface_npf "\\Device\\NPF_${iface_adapter}"

		set argv [lreplace $argv $dest_parm_idx $dest_parm_idx $iface_npf]
	}
}

# Determine name of temporary directory
for {set i 0} {$i < 20} {incr i} {
	append random_bin [format %c [expr {int(rand() * 256)}]]
}
binary scan $random_bin H* random

set srcdir [file join $::starkit::topdir files]
set dstdir [file join $tmpdir tcpdump-temp-$random]

proc cleanup {} {
	# Cleanup
	catch {
		::twapi::stop_service npf
	}
	catch {
		::twapi::delete_service npf
	}
	catch {
		file delete -force -- $::dstdir
	}
}

# Install exit handler to cleanup
rename exit _exit
proc exit args {
	cleanup
	_exit {*}$args
}

twapi::set_console_control_handler exit

# Run tcpdump
set exit 1
set npf_failed 0
if {[catch {
	## Create directory
	file delete -force -- $dstdir
	file mkdir $dstdir

	## Copy files to directory
	set filesdir [file join $dstdir files]
	file copy -- $srcdir $filesdir

	## Delete extraneous service
	catch {
		::twapi::stop_service npf
	}

	catch {
		::twapi::delete_service npf
	}

	## Install driver and start service
	if {[catch {
		set driver [file join $filesdir npf${bits}.sys]
		set driver [file nativename $driver]
		::twapi::create_service npf $driver -displayname "WinPcap Packet Driver (NPF)" -servicetype kernel_driver -starttype demand_start -errorcontrol ignore

		set started [::twapi::start_service npf -wait 60000]
		if {!$started} {
			error "npf did not start"
		}
	} npf_err]} {
		set npf_failed 1
	}

	## Launch tcpdump with the apropriate parameters
	set tcpdumpexe [file join $filesdir tcpdump.exe]
	exec -- $tcpdumpexe {*}$argv >&@ stdout

	set exit 0
} err]} {
	if {$npf_failed} {
		puts "NPF Failed: $npf_err"
		puts "Failed: $err"
	}

	set exit 1
}

# Terminate
exit $exit