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

This is a simple IDS that I'm building for a class. Right now it captures packets fine and whenever it captures a packet it compares it to the lines in the data.txt file. When an IP matching one in the data.txt file is captured, it writes a message to the logfile.txt. Then Ports are compared to data2.txt file and when they match, it is also written to the same logfile.txt. Which would be fine but my teacher wants to use split in order to compare IPs and Ports from the same data.txt file.

data.txt is just a list of IPs and data2.txt is just a list of port numbers. In the end I need to make use of a single data file.

She told us to make the data file look something like this.

i,s, {ip address you want to match here without the brackets} i,d, {domain name of the ip} p,s, {port number}

"i" stands for IP, and "s" stands for Source, so the source IP would be matched to this line. "i" in the second line is also for IP but the "d" is for the domain name which is just to print in the logfile what domain IP was found.

My classmates tried to explain to me how to use split to tell the program which line of the data file needs to be compared to what part in the packets I capture. I even got help on here before with the split but I still don't quite understand it.

#!/usr/bin/perl -w # --------------------------------------------------------- # testapp.pl (v 0.2): captures and dump packets; # based on Loris Degioanni's TestApp program in C # (see the Packet Capture Driver Developer's Pack). # This simple example shows how to capture raw packets # to the network using Win32::NetPacket. # This program is free software; you can redistribute it # and/or modify it under the same terms as Perl itself. # (c) 2003-2006 J-L Morel jlmorel@cpan.org # --------------------------------------------------------- use diagnostics; use strict; use warnings; use Win32::Console::ANSI; use Win32::NetPacket qw/ :ndis GetAdapterNames /; use Term::ReadKey; use NetPacket::Ethernet qw(:strip); use NetPacket::IP qw(:strip); use NetPacket::TCP; use NetPacket::UDP; use NetPacket::ICMP; $|++; use constant SizeOfInt => 4; # for word alignment # select the adapter my %desc; my @adpts = GetAdapterNames( \%desc ); @adpts > 0 or die "No adapter installed !\n"; my $i = 1; if ( @adpts > 1 ) { print "Adapters installed:\n\n"; print $i++, " - $desc{$_}\n $_\n" foreach @adpts; do { print "\nSelect the number of the adapter to open : "; $i = <STDIN>; chomp $i; } until ( $i =~ /^(\d)+$/ and 0 < $i and $i <= @adpts ); } # open the selected adapter my $nic = Win32::NetPacket->new( adapter_name => $adpts[ $i - 1 ], driver_buffer_size => 512 * 1024, # 512 kbytes kernel buffer read_timeout => 1000, # 1s timeout ) or die $@; $nic->SetHwFilter(NDIS_PACKET_TYPE_PROMISCUOUS); # set nic in promiscu +ous mode # print infos my ( $name, $description, $type, $speed, $ip, $mask, $mac ) = $nic->Ge +tInfo(); $description ||= $desc{$name}; $ip ||= '?.?.?.?'; $mask ||= '?.?.?.?'; $mac = join '-', unpack 'A2' x 6, $mac; print "Listening $name\n($description)\nMAC: $mac IP: $ip Mask: $mask\ +n"; print "** press [enter] to terminate\n"; # set user's buffer my $Buff; $nic->SetUserBuffer( $Buff, 128 * 1024 ); # main capture loop my $BytesReceived; while ( !ReadKey(-1) ) { # press (enter) to terminate $BytesReceived = $nic->ReceivePacket(); # capture the packets printPackets(); # print the packets } printf "\n\n%d packets received,\n%d packets lost.\n", $nic->GetStats; # ------ printPackets routine sub printPackets { my $nic = shift; my $offset = 0; while ( $offset < $BytesReceived ) { my ( $tv_sec, $tv_usec, $caplen, $datalen, $hdrlen ) = unpack 'llI +IS', substr $Buff, $offset; $offset += $hdrlen; my $data = substr $Buff, $offset, $datalen; # extract the datag +ram my $i = 0; my $eth_obj = NetPacket::Ethernet->decode($data); print "\nSource Mac: ", $eth_obj->{src_mac},"\n", "Dest. Mac: ", +$eth_obj->{dest_mac}; my $ip_obj=NetPacket::IP->decode(eth_strip($data)); print "\nDestination IP: ", $ip_obj->{dest_ip}, "\n"; print "Source IP: ", $ip_obj->{src_ip}, "\n"; if($ip_obj->{proto}==6){ print "Protocol: TCP\n";} elsif($ip_obj->{proto}==1){ print "Protocol: ICMP\n";} elsif($ip_obj->{proto}==17){ print "Protocol: UDP\n";} elsif($ip_obj->{proto}==34){ print "Protocol: 3PC\n";} else{ print "Protocol: $ip_obj->{proto}";} my @iparray; open READINGFILE, "data.txt" or die $!; open LOGFILE, ">>logfile.txt" or die $!; while(<READINGFILE>) { push (@iparray, $_); } close (READINGFILE) or die $!; foreach (@iparray) { chomp; if($ip_obj->{src_ip} eq $_) { print LOGFILE "Google's IP has been found\n"; } } my @portarray; open READINGFILE2, "data2.txt" or die $!; while(<READINGFILE2>) { push (@portarray, $_); } close (READINGFILE2) or die $!; my $tcp_obj=NetPacket::TCP->decode(ip_strip(eth_strip($data))); foreach (@portarray) { chomp; if($tcp_obj->{dest_port} eq $_) { print LOGFILE "Port number has been found\n"; } } close (LOGFILE) or die $!; ########### if ($ip_obj->{proto} == 6) {print "TCP\n"; print "Destination Port: ", $tcp_obj->{dest_port}, "\n"; print "Source Port: ", $tcp_obj->{src_port}, "\n"; print "Flags: "; #---------------------Flags if/statement if($tcp_obj->{flags} == 1) {print "FIN\n";} elsif($tcp_obj->{flags} == 2) {print "SYN\n";} elsif($tcp_obj->{flags} == 4) {print "RST\n";} elsif($tcp_obj->{flags} == 8) {print "PSH\n";} elsif($tcp_obj->{flags} == 16) {print "ACK\n";} elsif($tcp_obj->{flags} == 32) {print "URG\n";} elsif($tcp_obj->{flags} == 64) {print "ECE\n";} elsif($tcp_obj->{flags} == 128) {print "CWR\n";} elsif($tcp_obj->{flags} == 24) {print "ACK/PSH\n";} else {print " Undefined\n";} #--------------------End Flags if/statement print "Data: ", $tcp_obj->{data}, "\n";} #-------------------------END TCP PROTOCOL IF STATEMENTS #-------------------------UDP If/statement elsif ($ip_obj->{proto} == 17) { print "UDP\n"; my $udp_obj=NetPacket::UDP->decode(ip_strip(eth_strip($data))); + #Decode UDP #---------------------Print To GUI print "Destination Port: ", $udp_obj->{dest_port}, "\n"; print "Source Port: ", $udp_obj->{src_port}, "\n"; print "Data: ", $udp_obj->{data}, "\n";} #--------------------------End UDP elsif ($ip_obj->{proto} == 1) {print "ICMP\n"; my $icmp_obj=NetPacket::ICMP->decode(ip_strip(eth_strip($data))); + #Decode ICMP #-----Take out #------------------------------Switch Statement use Switch; switch ($icmp_obj->{code}) { case 0 {print "Echo Reply\n";} case 3 {print "Destination Unreachable\n";} case 5 {print "Redirect\n";} case 8 {print "Echo Request\n";} case 11 {print "Time Exceeded\n";} else {print " Undefined\n";} } }#---------------------END OF ICMP else {print $ip_obj->{proto}, " Undefined\n";} ############### #do same for other protocols # do { # local $, = ' '; # my $lg = substr $data, $i, 16; # printf "%.8X : ", $i; # $i += 16; # print unpack( 'H2' x 16, $lg ), ' ' x ( 16 - length $lg ); #$lg =~ s/[\x00-\x1F\x95\xFF]/./g; # print " $lg\n"; # } until $i >= $datalen; # Packet word alignment $offset = ( ( $offset + $caplen ) + ( SizeOfInt - 1 ) ) & ~( SizeOfInt - + 1 ); } } ###################################################################### +#####

The newest part starts at:

 my @iparray;

Thank you so much in advance! I'm sorry for being so new to perl. Our professor wants us to learn it on our own which is a slow, hard process on my own.

Replies are listed 'Best First'.
Re: Help Using Split and Arrays
by John M. Dlugosz (Monsignor) on Apr 23, 2011 at 01:35 UTC
    OK, you have lines containing something - comma - something - comma - remainder. Right?

    So split on the commas. More specifically, split on the first two commas only so I don't have to worry about any stray commas in the remainder.

    use Data::Dump qw(dump); my $s= 'a,b, this is the rest of the string, dude!'; my @results= split(/,/, $s); print dump \@results;
    Now, you might find stray whitespace around the commas, so try formulating a fancier pattern to match that.

      Thank you for replying.

      I'm new to arrays. Can I take the array that's storing the information pulled from the file and split it like you're doing the string you've written into the code?

      Something like this?

      my @newarray= split (/,/,$data);

      It may be easy but for some reason I can't word the questions I have right to get what I need. Maybe that's all I need to do.

        Each item in the array is one string. You need to read this book. I've seen free PDFs for that around the web. You might also try this page. You need to know about scalars and arrays as basic types, how to write loops, and probably everything else. So just start with a beginner book and work through it.

        my @samples= ('a,b,stuff', 'b, c , more stuff'); foreach my $line (@samples) { # work with $line here }
        See Foreach Loops in the Perl documentation.