From owner-freebsd-questions Sun Jun 17 11:21:45 2001 Delivered-To: freebsd-questions@freebsd.org Received: from x1-6-00-50-ba-de-36-33.kico1.on.home.com (d141-119-162.home.cgocable.net [24.141.119.162]) by hub.freebsd.org (Postfix) with ESMTP id A163037B414 for ; Sun, 17 Jun 2001 11:19:30 -0700 (PDT) (envelope-from genisis@istar.ca) Received: from localhost (genisis@localhost) by x1-6-00-50-ba-de-36-33.kico1.on.home.com (8.11.3/8.11.3) with ESMTP id f5HIOFo48205; Sun, 17 Jun 2001 14:24:15 -0400 (EDT) (envelope-from genisis@istar.ca) X-Authentication-Warning: x1-6-00-50-ba-de-36-33.kico1.on.home.com: genisis owned process doing -bs Date: Sun, 17 Jun 2001 14:24:14 -0400 (EDT) From: Dru X-X-Sender: To: Mike Meyer Cc: Subject: Re: script not found in /usr/local/etc/rc.d In-Reply-To: <15148.61274.704322.668319@guru.mired.org> Message-ID: <20010617141853.S48172-100000@x1-6-00-50-ba-de-36-33.kico1.on.home.com> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-questions@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG Hi Mike, Forgive the long post, as this time I'll include both scripts instead of sending them as attachments. (feel free to snip the appropriate portions) Thanks for the help guys :) Dru more /usr/local/etc/rc.d/mnwclient.sh #!/bin/sh # # mnwclient This shell script takes care of starting and stopping # myNetWatchman Agent for FreeBSD # # description: mnwclient # untested needs default paths of /bin and /usr/bin # Check that networking is up. #[ ${NETWORKING} = "no" ] && exit 0 # check if the mnwclient.rc file is present [ -f /etc/mnwclient.rc ] || exit 0 # check to see if mnwclient exists [ -f /usr/sbin/mnwclient ] || exit 0 if [ $# -eq 0 -o x$1 = xstart ]; then /usr/sbin/mnwclient -c /etc/mnwclient.rc & fi if [ x$1 = xstop ]; then /bin/kill `ps | grep 'perl.*mnwclient' | cut -f 1 -d " "` fi ************************************************************************* more /usr/sbin/mnwclient #!/usr/bin/perl -w ## ## mnwclient - a Perl client for myNetWatchman ## Copyright (C) 2001 Chad Wagner ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 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 General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## mnwclient -- a Perl client for myNetWatchman ## $Id: mnwclient,v 1.9 2001/05/01 03:46:12 wagnerch Exp $ use Getopt::Std; use IO::Socket; use POSIX; ## DEFAULTS ## ## configuration file, where configuration parameters are stored $mnwclientrc = "/etc/mnwclient.rc"; ## this is where Packet log kernel messages are logged, typically ## /var/log/messages, but may vary based on distribution. $logfile = "/var/log/messages"; ## user interface to upload packets for $interface = "ppp0"; ## default chain to inspect, typically 'input' @chaintbl = ("input"); ## location to write error messages, success, etc $errorlog = "/var/log/mnwclient.log"; ## gmt correction offset, in seconds. $gmt = 0; ## default delay interval between rescanning log $interval = 60; ## default dequeue interval in seconds. $dqinterval = 1; ## default backoff factor $backoff = 3; ## maximum backoff factor $maxbackoff = 600; ## default debug level $debug = 0; ## DO NOT MODIFY BELOW THIS LINE ## ## version number $mnwvers = "1.9"; ## this is the server and port $server = "www.mynetwatchman.com"; $port = 80; $script = "/insertwebreport.asp"; ## unbuffer i/o $| = 1; ## process switches and arguments getopts("i:c:l:e:zh", \%args); ## set overrides $mnwclientrc = $args{c} if defined $args{c}; ## override rc file $errorlog = $args{e} if defined $args{e}; ## override errors log ## check for invalid conditions, or help request if (defined $args{h}) { printf "%s [-c resource_file] [-l kernel_log_file] [-e errors_log_file]\n\t[-i interface]\n\n",$0; printf " -c resource_file data file that holds configuration parameters\n"; printf " -l kernel_log_file where the kernel logs dropped or filtered packets\n"; printf " -e errors_log_file where this client logs error messages\n"; printf " -i interface upload data for interface\n"; exit 1; } ## open pointer resource file if (open(FD,$mnwclientrc)) { $braces=0; @filtbl=(); while () { $_ =~ s/\n$//g; $_ =~ s/^\s*//g; $_ =~ s/\s*$//g; if (m/^#/ || m/^$/) { ## comment } elsif ((m/^interface\s+(.*)$/) && (!$braces)) { ## interface directive $interface=$1; } elsif ((m/^chain\s+(.*)$/) && (!$braces)) { ## chain directive @chaintbl=split(/,/,$1); } elsif ((m/^errors\s+(.*)$/) && (!$braces)) { ## errors log directive $errorlog=$1; } elsif ((m/^log\s+(.*)$/) && (!$braces)) { ## log directive $logfile=$1; } elsif ((m/^login\s+(.*)$/) && (!$braces)) { ## login directive $agtname=$1; } elsif ((m/^password\s+(.*)$/) && (!$braces)) { ## password directive $agtpass=$1; } elsif ((m/^server\s+(.*)$/) && (!$braces)) { ## server directive $server=$1; } elsif ((m/^port\s+(.*)$/) && (!$braces)) { ## port directive $port=$1; } elsif ((m/^proxy\s+(.*)$/) && (!$braces)) { ## proxy directive ($proxyserver,$proxyport) = split(/:/,$1,2); } elsif ((m/^debug(?:\s+(.*))?$/) && (!$braces)) { ## debug directive if ($1 ne "") { $debug = $1; } else { $debug=1; } } elsif ((m/^quiet$/) && (!$braces)) { ## quiet directive $quiet=1; } elsif ((m/^test$/) && (!$braces)) { ## test directive $test=1; } elsif ((m/^gmt\s+(.*)$/) && (!$braces)) { ## gmt directive $gmt=$1 * 3600; } elsif ((m/^retry\s+(.*)$/) && (!$braces)) { ## retry directive, ignored } elsif ((m/^interval\s+(.*)$/) && (!$braces)) { ## interval directive $interval=$1; } elsif ((m/^dqinterval\s+(.*)$/) && (!$braces)) { ## dqinterval directive $dqinterval=$1; } elsif ((m/^backoff\s+(.*)$/) && (!$braces)) { ## backoff directive $backoff=$1; } elsif ((m/^maxbackoff\s+(.*)$/) && (!$braces)) { ## maxbackoff directive $maxbackoff=$1; } elsif ((m/^filter\s+\{$/) && (!$braces)) { ## filter directive, open braces mode $braces=1; } elsif ((m/^\}$/) && ($braces)) { ## close braces mode $braces=0; } elsif ($braces) { ## braces mode if (m/^source\s+([0-9,\.]+)\s+netmask\s+([0-9,\.]+)$/) { ## filter-source/netmask directive push(@filtbl,[0,$1,$2]); } elsif ((m/^port\s+(\d+)(?:\s+proto\s+(\w+))?$/) || (m/^target\s+port\s+(\d+)(?:\s+proto\s+(\w+))?$/)) { ## filter-target/port/proto directive push(@filtbl,[1,$1,$2]); } elsif (m/^proto\s+(\w+)$/) { ## filter-proto directive push(@filtbl,[2,$1]); } elsif (m/^target\s+([0-9,\.]+)\s+netmask\s+([0-9,\.]+)$/) { ## filter-target/netmask directive push(@filtbl,[3,$1,$2]); } elsif (m/^source\s+port\s+(\d+)(?:\s+proto\s+(\w+))?$/) { ## filter-source/port/proto directive push(@filtbl,[4,$1,$2]); } elsif (m/^target\s+([0-9,\.]+)\s+netmask\s+([0-9,\.]+)\s+xchg\s+([0-9,\.]+)$/) { ## filter-target/netmask/xchg directive push(@filtbl,[5,$1,$2,$3]); } else { ## unknown filter directive printf STDERR "unknown filter directive encountered in configuration file, \"%s\"\n",$_; } } else { ## unknown directive printf STDERR "unknown directive encountered in configuration file, \"%s\"\n",$_; } } close(FD); } else { printf STDERR "failed to open \"%s\" for reading: %s\n",$mnwclientrc,$!; exit 1; } ## warn about resource file being world/group readable/writable $mode = (stat($mnwclientrc))[2]; &warning("configuration file is set world/group readable/writeable.\n") if ($mode & 077); ## override logfile, if set on command line $logfile = $args{l} if defined $args{l}; ## override interface, if set on command line $interface = $args{i} if defined $args{i}; ## check for agent name and password if (!defined $agtname || !defined $agtpass) { &fatal("agent name or password must be defined.\n"); } ## check for valid proxy port, if defined if (defined $proxyserver) { if (!$proxyport) { &fatal("proxy directive has invalid port, or undefined port.\n"); } } ## stat log file and get current size $size = (stat($logfile))[7]; $offset=$size; $offset=0 if defined $args{z}; ## initialize msgq list @msgq=(); ## report version, and state that we are running &printk("mnwclient version %s, monitoring \"%s\" starting at offset %lu\n",$mnwvers,$logfile,$offset); ## initialize several scalars here my($proto)=0; my(%protonum) = ( ## protocol table 'TCP' => 6, ## tcp 'tcp' => 6, ## tcp 'UDP' => 17, ## udp 'udp' => 17, ## udp 'ICMP' => 1, ## icmp 'icmp' => 1 ## icmp ); my($count); ## attack count my($match); ## match regex, used for checking for 'repeated' msgs my($success); ## match regex, used to submit report ## setup currdqinterval equal to dqinterval, and var for lastdq stamp my($currdqinterval) = $dqinterval; my($lastdq) = time; while (1) { ## stat log file and get current size $size = (stat($logfile))[7]; ## if offset is larger then size then logfile has been reset $offset=0 if ($offset > $size); ## read in log file, and store in data array open(FD,$logfile) || &fatal("unable to open kernel log for reading \"%s\": %s\n",$logfile,$!); seek(FD,$offset,SEEK_SET); while () { ## initialize scalars on each looping $count = 1; $success = 0; ## dump debug info &printk("debug: logread [%s]\n",$_) if ($debug >= 9); ## this is our regexp that we are looking to extract meaningful data from if (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+kernel:\s+Packet\s+log:\s+(\w+)\s+(REJECT|DENY)\s+(\w+)\s+PROTO=(\d+)\s+([0-9,\.]+):(\d+)\s+([0-9,\.]+):(\d+)/) { ## deal with ipchains log formatting if (&ischain($2) && $4 eq $interface) { @last = ($1,$5,$6,$7,$8,$9); $match = 1; $success = 1; } else { $match = 0; } } elsif (m/id=firewall/) { ## deal with sonicwall log formatting my($fwtime,$fwc,$fwm,$fwsrcaddr,$fwsrcport,$fwdstaddr,$fwdstport); if (m/time=\"(\d+-\d+-\d+\s+\d+:\d+:\d+(?:\s+UTC)?)\"/) { $fwtime=$1; } if (m/c=(\d+)/) { $fwc=$1; } if (m/m=(\d+)/) { $fwm=$1; } if (m/src=([\w,\.]+)(?::(\d+))?:WAN/) { $fwsrcaddr=$1; $fwsrcport=$2; } if (m/dst=([\w,\.]+)(?::(\d+):\w+)?/) { $fwdstaddr=$1; $fwdstport=$2; } $proto = 0; if ($fwc == 32) { my(%protocvt) = ( ## port/proto -- attack 22 => 1, ## icmp -- ping of death 23 => 0, ## ip -- ip spoof (unsupported) 27 => 6, ## tcp -- land 67 => 0, ## ??? -- ipsec auth failed (unsupported) 70 => 0, ## ??? -- ipsec dropped (unsupported) 72 => 6, ## tcp -- netbus 73 => 6, ## 31337/tcp -- back orifice 74 => 6, ## 1024/tcp -- net spy 75 => 6, ## 27374/tcp -- subseven 76 => 6, ## 2023/tcp -- ripper 77 => 6, ## 2565/tcp -- striker 78 => 17, ## 13000/udp -- senna spy 79 => 6, ## 16969/tcp -- priority 80 => 6, ## 9989/tcp -- inikiller 81 => 1, ## icmp -- smurf 82 => 0, ## ??? -- probable port scan (unsupported) 83 => 0, ## ??? -- probable port scan (unsupported) 84 => 6, ## tcp -- syn port scan 173 => 6 ## tcp -- fin port scan ); $proto = $protocvt{$fwm}; } else { my(%protocvt) = ( ## packets dropped 64 => 6, ## tcp 128 => 17, ## udp 256 => 1 ## icmp ); $proto = $protocvt{$fwc}; } ## check for fwdstport and icmp proto, if not defined assume it is ## type 0 icmp (echo-request) $fwdstport=0 if ($proto == 1 && !defined $fwdstport); ## check for fwsrcport, if not defined then assign it as -1, which is ## 'not displayed' $fwsrcport=-1 if (!defined $fwsrcport); ## must have all necessary fields, and protocol nonzero if (defined $fwtime && defined $fwsrcaddr && defined $fwsrcport && defined $fwdstaddr && defined $fwdstport && $proto) { @last = ($fwtime,$proto,$fwsrcaddr,$fwsrcport,$fwdstaddr,$fwdstport); $match = 1; $success = 1; } else { $match = 0; } } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+portsentry\[\d+\]:\s+attackalert:\s+(.+\s+scan|Packet|Connect)\s+from\s+host:\s+\S+\/([0-9,\.]+)\s+to\s+(\w+)\s+port:\s+(\d+)/) { ## deal with portsentry log formatting $proto = $protonum{$4}; @last = ($1,$proto,$3,-1,-1,$5); $match = 1; $success = 1; } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\S+:\s+ipfw:\s+\d+\s+(REJECT|DENY)\s+(TCP|UDP)\s+([0-9,\.]+):(\d+)\s+([0-9,\.]+):(\d+)\s+(\w+)\s+via\s+(\w+)/i) { ## deal with ipfw log formatting udp/tcp (freebsd) $proto = $protonum{$3}; if (&ischain($8) && $9 eq $interface) { @last = ($1,$proto,$4,$5,$6,$7); $match = 1; $success = 1; } else { $match = 0; } } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\S+:\s+ipfw:\s+\d+\s+(REJECT|DENY)\s+(ICMP):(\d+)\.(\d+)\s+([0-9,\.]+)\s+([0-9,\.]+)\s+(\w+)\s+via\s+(\w+)/i) { ## deal with ipfw log formatting icmp (freebsd) if (&ischain($8) && $9 eq $interface) { @last = ($1,1,$6,$4,$7,$5); $match = 1; $success = 1; } else { $match = 0; } } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\d+:\s+([\*]*)(\w+\s+\d+\s+\d+:\d+:\d+)(?:\.\d+\s+\w+)?:\s+\S+:\s+list\s+(\d+)\s+denied\s+(tcp|udp)\s+([0-9,\.]+)\((\d+)\)\s+->\s+([0-9,\.]+)\((\d+)\),\s+(\d+)\s+packet/i) { ## deal with cisco format tcp/udp if (&ischain($4)) { $proto = $protonum{$5}; @last = ($1,$proto,$6,$7,$8,$9); ## use date from router if not marked invalid @last = ($3,$proto,$6,$7,$8,$9) if ($2 eq ""); $count = $10; $match = 1; $success = 1; } else { $match = 0; } } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\d+:\s+([\*]*)(\w+\s+\d+\s+\d+:\d+:\d+)(?:\.\d+\s+\w+)?:\s+\S+:\s+list\s+(\d+)\s+denied\s+(icmp)\s+([0-9,\.]+)\s+->\s+([0-9,\.]+)\s+\((\d+)\/(\d+)\),\s+(\d+)\s+packet/i) { ## deal with cisco format icmp if (&ischain($4)) { @last = ($1,1,$6,$8,$7,$9); ## use date from router if not marked invalid @last = ($3,1,$6,$8,$7,$9) if ($2 eq ""); $count = $10; $match = 1; $success = 1; } else { $match = 0; } } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+named\[\d+\]:\s+(denied|unapproved)\s+query\s+from\s+\[([0-9,\.]+)\]\.(\d+)\s+for\s+\"version\.bind/i) { ## deal with version.bind named requests @last = ($1,6,$3,$4,-1,53); $match = 1; $success = 1; } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\S+\s+IP\[Src=([0-9,\.]+)\s+Dst=([0-9,\.]+)\s+(\w+)(?:\s+spo=(\d+)\s+dpo=(\d+))?\]\s*\}\s*S(\d+)>R(\d+)(m|n)D/) { ## (syslog format) zyxel prestige 314/netgear rt314 router ## only 'm'atched or 'n'ot matched 'D'rops if (&ischain($7)) { $proto = $protonum{$4}; if ($proto == 1) { @last = ($1,$proto,$2,-1,$3,8); } else { @last = ($1,$proto,$2,$5,$3,$6); } $match = 1; $success = 1; } else { $match = 0; } } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+kernel:\s+(.*):\s+IN=(\S*)\s+OUT=(\S*)\s+(?:MAC=[\d,a-f,:]+\s+)?SRC=([\d,\.]+)\s+DST=([\d,\.]+)\s+LEN=\d+\s+TOS=[\w,x]+\s+PREC=[\w,x]+\s+TTL=\d+\s+ID=\d+\s+(?:DF\s+)?PROTO=(\w+)(?:\s+TYPE=(\d+)\s+CODE=(\d+))?(?:\s+SPT=(\d+)\s+DPT=(\d+))?/) { ## iptables syslog format if (&ischain($2) && $3 eq $interface) { $proto = $protonum{$7}; if ($proto == 1) { ## icmp packet @last = ($1,$proto,$5,-1,$6,$8); } else { ## tcp/udp/? packet @last = ($1,$proto,$5,$10,$6,$11); } $match = 1; $success = 1; } else { $match = 0; } } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\%PIX-(\d+)-(\d+):\s+Deny\s+inbound\s+(UDP)\s+from\s+([\d,\.]+)\/(\d+)\s+to\s+([\d,\.]+)\/(\d+)/ || m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\%PIX-(\d+)-(\d+):\s+Deny\s+inbound\s+(\w+)\s+src\s+\w+:\s*([\d,\.]+)\/(\d+)\s+dst\s+\w+:([\d,\.]+)\/(\d+)/ || m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\%PIX-(\d+)-(\d+):\s+Dst\s+IP\s+is\s+network\/broadcast\s+IP,\s+translation\s+creation\s+failed\s+for\s+(\w+)\s+src\s+\w+:\s*([\d,\.]+)\/(\d+)\s+dst\s+\w+:\s*([\d,\.]+)\/(\d+)/ || m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\%PIX-(\d+)-(\d+):\s+Inbound\s+(TCP)\s+connection\s+denied\s+from\s+([\d,\.]+)\/(\d+)\s+to\s+([\d,\.]+)\/(\d+)/) { ## PIX-2-106006, inbound UDP packet ## PIX-3-106010, inbound TCP/UDP packet, broadcast destination ## PIX-3-305006, inbound TCP/UDP packet, broadcast destination ## PIX-2-106001, inbound TCP packet $proto = $protonum{$4}; @last = ($1,$proto,$5,$6,$7,$8); $match = 1; $success = 1; } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\%PIX-(\d+)-(\d+):\s+Deny\s+inbound\s+(icmp)\s+src\s+\w+:\s*([\d,\.]+)\s+dst\s+\w+:\s*([\d,\.]+)\s+\(type\s+(\d+),\s+code\s+(\d+)\)/ || m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\%PIX-(\d+)-(\d+):\s+Dst\s+IP\s+is\s+network\/broadcast\s+IP,\s+translation\s+creation\s+failed\s+for\s+(icmp)\s+src\s+\w+:\s*([\d,\.]+)\s+dst\s+\w+:\s*([\d,\.]+)\s+\(type\s+(\d+),\s+code\s+(\d+)\)/) { ## PIX-3-106010, inbound ICMP packet, broadcast destination ## PIX-3-305006, inbound ICMP packet, broadcast destination $proto = $protonum{$4}; @last = ($1,$proto,$5,-1,$6,$7); $match = 1; $success = 1; } elsif (m/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+\S+\s+\%PIX-(\d+)-(\d+):\s+Deny\s+(IP)\s+from\s+([\d,\.]+)\s+to\s+([\d,\.]+),\s+IP\s+options/) { ## PIX-2-106012, inbound IP packet ## currently we do nothing with this packet } elsif (m/^\w+\s+\d+\s+\d+:\d+:\d+\s+\S+\s+\%PIX-(\d+)-(\d+):\s+.{0,1}last\s+message\s+repeated\s+(\d+)\s+time/ && $match) { ## our last message was a packet log message, so lets repeated the ## previously collected data n times. $count = $3; $success = 1; } elsif (m/^\w+\s+\d+\s+\d+:\d+:\d+\s+\S+\s+last\s+message\s+repeated\s+(\d+)\s+times/ && $match) { ## our last message was a packet log message, so lets repeated the ## previously collected data n times. $count = $1; $success = 1; } else { ## reset match, and update offset $match = 0; $offset = tell(FD); } if ($success) { $offset = tell(FD); &queue_attack($last[0],$last[1],$last[2],$last[3],$last[4],$last[5],$count); } } close(FD); ## enter interval delay loop, we want to sleep currdqinterval seconds and ## pop a queued attack off the stack and upload it while we are waiting ## for the interval delay loop to elapse. local($then) = time; while ((time - $then) < $interval) { if (($currdqinterval - (time - $lastdq)) > $interval) { &printk("debug: (currdqinterval %lu - (time %lu - lastdq %lu)) > interval %lu\n",$currdqinterval,time,$lastdq,$interval) if ($debug >= 2); ## if interval is greater than current remaining dqinterval then ## just sleep the interval sleep($interval); } elsif (($currdqinterval - (time - $lastdq)) > $dqinterval) { &printk("debug: (currdqinterval %lu - (time %lu - lastdq %lu)) > dqinterval %lu\n",$currdqinterval,time,$lastdq,$dqinterval) if ($debug >= 2); ## if the current remaining dqinterval is greater than dqinterval then ## just sleep the remaining value less one dqinterval sleep($currdqinterval - (time - $lastdq) - $dqinterval); } else { &printk("debug: sleeping currdqinterval %lu - (time %lu - lastdq %lu)\n",$currdqinterval,time,$lastdq) if ($debug >= 2); ## otherwise just sleep the current remaining dqinterval, and then ## dequeue an attack sleep($currdqinterval - (time - $lastdq)); &dequeue_attack; $lastdq = time; } } } ## looks up protocol number in list and shows given name, only icmp, tcp and ## udp are in here, as they are likely most of the traffic. sub show_proto_name { my($num) = shift if @_; my(%protonum) = ( ## protocol table 1 => 'icmp', ## icmp 6 => 'tcp', ## tcp 17 => 'udp' ## udp ); &printk("debug: show_proto_name returning results %s\n",($protonum{$num} eq "" ? $num : $protonum{$num})) if ($debug >= 2); if ($protonum{$num} ne "") { ## we got a valid protocol number, return it's name return $protonum{$num}; } else { ## we got a invalid protocol number, return it's number return $num; } } ## checks to see if matches input chain ## 0 on failure, 1 on success sub ischain { my($in) = shift; foreach (@chaintbl) { if ($in eq $_) { &printk("debug: ischain returning true, %s == %s\n",$in,$_) if ($debug >= 2); return 1; } } &printk("debug: ischain returning false\n") if ($debug >= 2); return 0; } ## checks to see if source address, port, or port and protocol are filtered sub isfiltered { my($proto) = shift; my($srcaddr) = shift; my($srcport) = shift; my($dstaddr) = shift; my($dstport) = shift; my($newdstaddr); my($retcode) = 0; &printk("debug: isfiltered called with arguments %s,%s,%s,%s,%s\n", $$proto,$$srcaddr,$$srcport,$$dstaddr,$$dstport) if ($debug >= 2); ## parse through filter table foreach (@filtbl) { if (@$_[0] == 0) { ## source addr filter if (&maskaddress(@$_[1],@$_[2]) == &maskaddress($$srcaddr,@$_[2])) { $retcode=1; last; } } elsif (@$_[0] == 1) { ## target port filter if (@$_[1] == $$dstport) { ## target port is a filter match if (defined(@$_[2])) { ## is proto specified, at all? if (@$_[2] eq &show_proto_name($$proto)) { $retcode=1; ## proto and port match, reject last; } } else { ## no proto, port already matchs, so reject $retcode=1; last; } } } elsif (@$_[0] == 2) { ## proto filter if (@$_[1] eq &show_proto_name($$proto)) { $retcode=1; ## protocol matches, reject last; } } elsif (@$_[0] == 3) { ## destination addr filter if (&maskaddress(@$_[1],@$_[2]) == &maskaddress($$dstaddr,@$_[2])) { $retcode=1; last; } } elsif (@$_[0] == 4) { ## source port filter if (@$_[1] == $$srcport) { ## source port is a filter match if (defined(@$_[2])) { ## is proto specified, at all? if (@$_[2] eq &show_proto_name($$proto)) { $retcode=1; ## proto and port match, reject last; } } else { ## no proto, port already matchs, so reject $retcode=1; last; } } } elsif (@$_[0] == 5) { ## target address exchange if (&maskaddress(@$_[1],@$_[2]) == &maskaddress($$dstaddr,@$_[2])) { $newdstaddr = @$_[3]; ## address is a match, store the new dstaddr ## in a scalar for use after parsing further ## filter rules } } else { ## unknown filter element &warning("unknown filter element, type=%d\n",@$_[0]); } } ## okay, we did a target...xchg, need to reparse filter table with new ## dstaddr. if (defined $newdstaddr) { $$dstaddr = $newdstaddr; $retcode = &isfiltered($proto,$srcaddr,$srcport,$dstaddr,$dstport); } &printk("debug: isfiltered returning results %s\n",$retcode) if ($debug >= 2); return $retcode; } ## apply netmask to address and return result sub maskaddress { my($address) = shift; my($netmask) = shift; &printk("debug: maskaddress returning results %s\n",&addr_to_32($address) & &addr_to_32($netmask)) if ($debug >= 2); return (&addr_to_32($address) & &addr_to_32($netmask)); } ## convert dotted ip notation to 32-bit number sub addr_to_32 { my($address) = shift; my($a1,$a2,$a3,$a4); ($a1,$a2,$a3,$a4) = split(/\./,$address); &printk("debug: addr_to_32 returning results %s\n",($a1 << 24) | ($a2 << 16) | ($a3 << 8) | $a4) if ($debug >= 2); return ($a1 << 24) | ($a2 << 16) | ($a3 << 8) | $a4; } ## translate date into format required, and utc sub transdate { my($date) = shift; my($time_t); my(%monnum) = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11 ); my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); ## if date is in correct format, translate it to utc if ($date =~ m/^(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)/) { ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $time_t = POSIX::mktime($5,$4,$3,$2,$monnum{$1},$year,0,0,$isdst); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($time_t + $gmt); return sprintf "%04d-%02d-%02d %02d:%02d:%02d",($year + 1900), ($mon + 1),$mday,$hour,$min,$sec; } elsif ($date =~ m/^(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)\s+UTC/) { return sprintf "%04d-%02d-%02d %02d:%02d:%02d",$1,$2,$3,$4,$5,$6; } elsif (($date =~ m/^(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/) || ($date =~ m/^(\d+)\/(\d+)\/(\d+),(\d+):(\d+):(\d+)/)) { ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $time_t = POSIX::mktime($6,$5,$4,$3,($2 - 1),($1 - 1900),0,0,$isdst); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($time_t + $gmt); return sprintf "%04d-%02d-%02d %02d:%02d:%02d",($year + 1900), ($mon + 1),$mday,$hour,$min,$sec; } ## otherwise we use current utc time ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(time); return sprintf "%04d-%02d-%02d %02d:%02d:%02d",($year + 1900), ($mon + 1),$mday,$hour,$min,$sec; } ## adds attack data to outbound queue sub queue_attack { my($datetime) = shift; my($proto) = shift; my($srcaddr) = shift; my($srcport) = shift; my($dstaddr) = shift; my($dstport) = shift; my($count) = shift; ## we are going to do some prefiltering, even though in some cases we ## don't know the destination address if (!&isfiltered(\$proto,\$srcaddr,\$srcport,\$dstaddr,\$dstport)) { ## initialize some local variables my($mqe); my($success) = 0; ## first thing we want to do is find a matching entry already in the ## queue, we report time on first attack, this shouldn't be a problem ## unless the interval is set too large, say more than 2 minutes. foreach $mqe (@msgq) { ## if this attack matches a previously queued one then increment ## the attack count. criteria for matching is same proto, ## source address, dest address, dest port. if (@$mqe[1] == $proto && @$mqe[2] eq $srcaddr && @$mqe[4] eq $dstaddr && @$mqe[5] == $dstport) { ## add the attack count of this one to the queued one @$mqe[6] += $count; &printk("debug: incq: %s,%s,%s,%s,%s,%s,%s\n", @$mqe[0],@$mqe[1],@$mqe[2],@$mqe[3],@$mqe[4],@$mqe[5], @$mqe[6]) if ($debug); $success = 1; last; } } ## if it wasn't already in the queue, add it now if (!$success) { ## add it to the outbound attack queue push(@msgq,[&transdate($datetime),$proto,$srcaddr,$srcport,$dstaddr,$dstport,$count]); &printk("debug: addq: %s,%s,%s,%s,%s,%s,%s\n", &transdate($datetime),$proto,$srcaddr,$srcport,$dstaddr,$dstport, $count) if ($debug); } } } ## dequeue attack and upload to server sub dequeue_attack { my($datetime,$proto,$srcaddr,$srcport,$dstaddr,$dstport,$count); my($lastmq,@mqe); ## only process if there is something in queue if ($#msgq >= 0) { ## pull last entry out, and store it in some local variables $lastmq = $msgq[$#msgq]; @mqe = @$lastmq; $datetime = $mqe[0]; $proto = $mqe[1]; $srcaddr = $mqe[2]; $srcport = $mqe[3]; $dstaddr = $mqe[4]; $dstport = $mqe[5]; $count = $mqe[6]; ## attempt to submit the report, if successful then pop it off the msgq if (&submit_report($datetime,$proto,$srcaddr,$srcport,$dstaddr,$dstport,$count)) { ## we can officially pop it off the stack now, since it was ## successfully uploaded. pop(@msgq); &printk("debug: popq: %s,%s,%s,%s,%s,%s\n", $datetime,$proto,$srcaddr,$srcport,$dstaddr,$dstport, $count) if ($debug); } else { ## backoff factor, calculate into currdqinterval $currdqinterval *= $backoff; ## set currdqinterval to maxbackoff if we exceed it $currdqinterval = $maxbackoff if ($currdqinterval > $maxbackoff); ## failed, dump whatever server responded with &warning("unable to upload %d attack(s) from %s:%d to %s:%d/%s, dequeue interval backing off to %lu seconds.\n",$count,$srcaddr,$srcport,$dstaddr,$dstport,&show_proto_name($proto),$currdqinterval); } } } ## uploads data to server and parses ## returns 0 on failure, 1 on success sub submit_report { my($datetime) = shift; my($proto) = shift; my($srcaddr) = shift; my($srcport) = shift; my($dstaddr) = shift; my($dstport) = shift; my($count) = shift; my($request); my($output); my($response); my($sd); my($success) = 0; if ($test) { if (!&isfiltered(\$proto,\$srcaddr,\$srcport,\$dstaddr,\$dstport)) { ## we are in 'test' mode, don't actually upload data &printk("upload %d attack(s) from %s%s to %s%d/%s successful (test mode).\n",$count,$srcaddr,($srcport >= 0 ? sprintf(":%d",$srcport) : ""),($dstaddr ne "-1" ? sprintf("%s:",$dstaddr) : ""),$dstport,&show_proto_name($proto)); } return 1; } ## open new socket to server { local $^W = 0; if (defined $proxyserver && defined $proxyport) { $sd = IO::Socket::INET->new( PeerAddr => $proxyserver, PeerPort => $proxyport, Proto => 'tcp'); ## start building HTTP get request, via proxy $output = sprintf "GET http://%s:%lu%s",$server,$port,$script; } else { $sd = IO::Socket::INET->new( PeerAddr => $server, PeerPort => $port, Proto => 'tcp'); ## start building HTTP get request $output = sprintf "GET %s",$script; } if (!defined($sd)) { ## socket error, we bail out with a failure to retry later &warning("cannot connect to %s: socket: %s\n",$server,$@); return 0; } } ## we only want to probe the IP address if we don't know it, basically for ## log formats such as portsentry. if ($dstaddr eq "-1") { &printk("debug: dstaddr is %s, probing\n",$dstaddr) if ($debug); $dstaddr = sprintf("%s.%s.%s.%s",unpack("C4",(unpack("S n a4 x8",getsockname($sd)))[2])); &printk("debug: acquired %s address from socket probe\n",$dstaddr) if ($debug); } ## check to see if this firewall entry is filtered if (&isfiltered(\$proto,\$srcaddr,\$srcport,\$dstaddr,\$dstport)) { ## packet is filtered, return with a success code &printk("debug: packet is filtered, dropping\n") if ($debug); return 1; } ## build our data submission portion of url $request = sprintf "AgentEmail=%s&AgentPassword=%s&AttackerIP=%s&DestPort=%s&VictimIP=%s&AttackCount=%s&AttackDateTime=%s&ProtocolID=%s",$agtname,$agtpass,$srcaddr,$dstport,$dstaddr,$count,$datetime,$proto; ## convert spaces to %20 $request =~ s/ /%20/g; ## attach data to end of get $output .= sprintf "?%s HTTP/1.0\n",$request; ## build out HTTP GET request $output .= sprintf "Host: %s\n",$server; $output .= "Content-Type: application/x-www-form-urlencoded\n"; $output .= sprintf "User-Agent: myNetWatchman Perl Agent/%s\n\n",$mnwvers; ## send it via the socket created print $sd $output; ## print debugging, if requested &printk("debug: send [%s]\n",$output) if ($debug >= 10); ## read in data from socket, setup for failure $success=0; $response=""; while (<$sd>) { $response .= $_; &printk("debug: read [%s]\n",$_) if ($debug >= 10); if (m/Attack\s+Report\s+Insert\s+Successful/) { ## we were successful, success should be 1 $success=1; } } close($sd); if (!$success) { if ($response =~ m/Error:\s+(.*?)
/) { &warning("error response returned: %s\n",$1); } else { &warning("unknown response on attack insert from %s.\n",$server); } return 0; } else { ## upload successful &printk("upload %d attack(s) from %s%s to %s:%d/%s successful.\n",$count,$srcaddr,($srcport >= 0 ? sprintf(":%d",$srcport) : ""),$dstaddr,$dstport,&show_proto_name($proto)); $currdqinterval = $dqinterval; return 1; } ## should never reach this far return 0; } ## warning message sub warning { printf STDERR "warning: " if (!$quiet); printf STDERR @_ if (!$quiet); &printk(@_); } ## fatal message sub fatal { printf STDERR "fatal: "; printf STDERR @_; &printk(@_); exit 1; } ## print kernel style message to custom log file sub printk { my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); my(%months) = ( 0 => 'Jan', 1 => 'Feb', 2 => 'Mar', 3 => 'Apr', 4 => 'May', 5 => 'Jun', 6 => 'Jul', 7 => 'Aug', 8 => 'Sep', 9 => 'Oct', 10 => 'Nov', 11 => 'Dec' ); ## open log file for appending open(LOGMSG,">>".$errorlog) || die "fatal: unable to append to error log: $!\n"; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); printf LOGMSG "%s %2s %02d:%02d:%02d mnwclient[%d]: ",$months{$mon},$mday, $hour,$min,$sec,$$; printf LOGMSG @_; close(LOGMSG); } On Sun, 17 Jun 2001, Mike Meyer wrote: > Dru types: > > However, when I try to start the script manually or when I reboot, I get > > an error message stating the script is not found: > > > > /etc/rc: /usr/local/etc/rc.d/mnwclient.sh: not found > > > > What am I missing here besides my sanity? I've attached the script if that > > helps. > > The #! line in the script is fubar for some reason that's causing the > kernel exec to fail. The report back to the shell is that the file > isn't executable (stupid, but apparently required by Posix), so the > shell reports that it can't find the executable. > > Joe Clark's guess - that it's pointing at the wrong place - is the > usual cause for that. There are other things that might make it do > that as well. > > Can you send just that line? I know you attached the script, but > freebsd.org's mail digester eats the MIME headers, so my mailer can't > decode what you sent :-(. > > -- > Mike Meyer http://www.mired.org/home/mwm/ > Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information. > > To Unsubscribe: send mail to majordomo@FreeBSD.org > with "unsubscribe freebsd-questions" in the body of the message > > > > To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-questions" in the body of the message