adismaug has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks
I am trying to write a web application that will get input from the user, run a TCPDUMP command on the server, analyze the output and display it on the web page.
Since it is a time consuming task I used, for a template, the script from the excellent article:
http://www.stonehenge.com/merlyn/LinuxMag/col39.html
In this script I exec another perl script that does the TCPDUMP job.
The thing is that I am unable to retrive the data from the second script as the TCPDUMP command returned the error “tcpdump: socket: Operation not permitted“ (maybe a tty problem?)
Your help please.
This is the main script and the second script:

#!/usr/bin/perl -T use strict; $|++; $ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/ +sbin"; use CGI qw(:all delete_all escapeHTML); if (my $session = param('session')) { # returning to pick up session d +ata my $cache = get_cache_handle(); my $data = $cache->get($session); unless ($data and ref $data eq "ARRAY") { # something is wrong show_form(); exit 0; } print header; print start_html(-title => "TCPDUMP Host Results", ($data->[0] ? () : (-head => ["<meta http-equiv=refresh content=5>"]))); print h1("TCPDUMP Host Results"); print pre(escapeHTML($data->[1])); print p(i("... continuing ...")) unless $data->[0]; print end_html; } elsif (my $host = param('host')) { # returning to select host if ($host =~ /^([a-zA-Z0-9.\-]{1,100})\z/) { # create a session $host = $1; # untainted now my $session = get_session_id(); my $cache = get_cache_handle(); $cache->set($session, [0, ""]); # no data yet if (my $pid = fork) { # parent does delete_all(); # clear parameters param('session', $session); print redirect(self_url()); } elsif (defined $pid) { # child does close STDOUT; # so parent can go on unless (open F, "-|") { open STDERR, ">&=1"; exec "/var/www/cgi-bin/tcpdump/scripts/srcGETrootStat. +pl", $host; die "Cannot execute tcpdump: $!"; } my $buf = ""; while (<F>) { $buf .= $_; $cache->set($session, [0, $buf]); } $cache->set($session, [1, $buf]); exit 0; } else { die "Cannot fork: $!"; } } else { show_form(); } } else { # display form show_form(); } exit 0; sub show_form { print header, start_html("TCPDUMP Host"), h1("TCPDUMP"); print start_form; print submit('tcpdump to this host:'), " ", textfield('host'); print end_form, end_html; } sub get_cache_handle { require Cache::FileCache; Cache::FileCache->new ({ namespace => 'perl', username => 'nobody', default_expires_in => '30 minutes', auto_purge_interval => '4 hours', }); } sub get_session_id { require Digest::MD5; Digest::MD5::md5_hex(Digest::MD5::md5_hex(time().{}.rand().$$)); } ###################### script 2 ################### #!/usr/bin/perl use Term::ANSIColor; use Socket; $commandSrcIb = "/usr/sbin/tcpdump -s 44 -vv -i eth1 -nn -c 100 'tcp[2 +2:4] = 0x54202F20' and dst port 80 -w /tmp/srcGetRoot.cap"; &calcNormal($commandSrcIb); sub calcNormal { @subCommand = @_; $count = 0; @date = qx { date '+%Y-%m-%d %H:%M:%S' }; chomp($date[0]); print "$date[0]\n"; `$subCommand[0]`; open(STDIN,"/usr/sbin/tcpdump -nn -r /tmp/srcGetRoot.cap |") || di +e "I can't open tcpdump."; while (<>) { $packet = $_; $packetArray = $_; $packet =~ s/ (\d+\.\d+\.\d+\.\d+)\.(\d+)\b/ $1 $2 /g; @split = split(" ", $packet); $activitySRC{$split[2]}++; $srcTime[$count] = "$split[0] $split[2]\n"; $count++; } foreach $host ( sort { $activitySRC{$b} <=> $activitySRC{$a} } + keys %activitySRC) { if ($activitySRC{$host} > 20) { @getHOST = grep(/$host/, @srcTime); chomp($getHOST[$#getHOST]); chomp($getHOST[0]); @startTime = split(/\:/, $getHOST[0]); $startTime = ($startTime[1] * 60) + $startTime[2]; @endTime = split(/\:/, $getHOST[$#getHOST]); $endTime = ($endTime[1] * 60) + $endTime[2]; $diffTime = $endTime - $startTime; $GETPerSec = $activitySRC{$host} / $diffTime; print (color(yellow),"$activitySRC{$host} \/ GET for $ +host, $GETPerSec Get Per Second [Total Time $diffTime]",color("reset" +),"\n"); undef(@getHOST); } else { next; } } undef %activitySRC; @date = qx { date '+%Y-%m-%d %H:%M:%S' }; chomp($date[0]); print "$date[0]\n"; }
Regards,
Adi.

Replies are listed 'Best First'.
Re: WEB CGI TCPDUMP
by Corion (Patriarch) on Jul 16, 2009 at 09:14 UTC

    This is likely a permissions problem, not a tty problem. The user your webserver is running your script as does not have the permissions to read raw network data from the network card. On unixish systems, traditionally only the root user account is allowed to do so, so you might have to find a way to communicate to the sniffing process that runs as root.

      the script is running as user apache, how can i change that?

        You don't want to change that, seriously.

        Running any program as root is a potential security risk for the machine and other machines in the same network. Running a program that is accessible via the network as root is a recipe for certain disaster. Ask your security person or your system administrator about what options are available to you.

        I'm not exactly sure what benefit running tcpdump via CGI over the network has for you over simply running tcpdump via a ssh login. But if you're convinced that CGI is a must, I recommend having a cron job or daemon program that runs tcpdump as root and writes the output to a known, fixed location. Potentially you can submit new jobs to that program by writing a file with the job parameters to a known location where the daemon program picks them up.