From lsawyer at gci.com Tue Apr 17 13:11:56 2001 From: lsawyer at gci.com (Leif Sawyer) Date: Wed Aug 4 23:56:49 2004 Subject: Bizarre Question Message-ID: Here's a question for you semi-advanced perl guru's out there. First, a little background so this makes sense: I have a hash'd array: %services with multiple dimensions: $services{$ACL}{$proto}{$destport} = count If this sounds a little familiar, i'm parsing the syslog output of a cisco router's ACL list. Simply put, ACL is an array of found lists like: $services{"input-1"} $services{"input-2"} $services{"input-3"} proto is the types of protocols found per ACL list: $services{"input-1"}{"udp"} $services{"input-1"}{"tcp"} $services{"input-1"}{"icmp"} destport is of course, the destination port that the connection terminated to for the protocol type: $services{"input-1"}{"tcp"}{"23"} $services{"input-1"}{"tcp"}{"110"} $services{"input-1"}{"tcp"}{"80"} at the very tail of this, is the count of packets per service $services{"input-1"}{"tcp"}{"23"} = 2098 $services{"input-1"}{"tcp"}{"110"} = 1 $services{"input-1"}{"tcp"}{"80"} = 2983242 What I'm trying to do, is print out a list of ports, by protocol, for each ACL. And i'd like the ports sorted by the number of packets, descending. ################################################### # # Report #1, most popular dest host(s) by acl # my($acl,$dest, $proto,$port); my (@ports); print "!!---------!! Most Popular Protocol Violations !!---------!!\n"; foreach $acl (sort keys %service) { print "ACL: $acl\n"; foreach $proto (sort keys %{$service{$acl}}) { print "Protocol: $proto\n"; ############### Attempt one ############ if (1) { foreach $port (sort mostusedsvc keys %{$service{$acl}{$proto}}) { my($name,$aliases,$p,$t) = getservbyport($port,$proto); print "Port: $port ($name) = " . $service{$acl}{$proto}{$port} . "\n"; } } else { ############### Attempt two ############ @ports = sort { $service{$acl}{$proto}{$b} <=> $service{$acl}{$proto}{$b} } keys %{$service{$acl}{$proto}}; foreach $port ( @ports ) { my($n,$a,$p,$t) = getservbyport($port,$proto); print "Port: $port ($n) = " . $service{$acl}{$proto}{$port} . "\n"; } } ######################################### print "\n"; } print "\n"; } sub mostusedsvc { $service{$acl}{$proto}{$b} <=> $service{$acl}{$proto}{$a} } ----------------------- But, neither of these seem to work. It prints out the data, just not sorted. I'm probably missing something obvious, but at this point, my brain hurts. :-) Thanks for any insight. Leif ================================================= Mailing list info: If at any time you wish to (un|re)subscribe to the list send the request to majordomo@hfb.pm.org. All requests should be in the body, and look like such subscribe anchorage-pm-list unsubscribe anchorage-pm-list From corliss at alaskapm.org Tue Apr 17 16:24:26 2001 From: corliss at alaskapm.org (corliss@alaskapm.org) Date: Wed Aug 4 23:56:49 2004 Subject: Bizarre Question In-Reply-To: Message-ID: On Tue, 17 Apr 2001, Leif Sawyer wrote: > What I'm trying to do, is print out a list of ports, by protocol, > for each ACL. And i'd like the ports sorted by the number of packets, > descending. One question: do you want each subset to be sorted by packet count, or the entire list sorted by packet count? Obviously, that makes a huge difference. To just sort it by acl, protocol, and packet count, in that order, something like this would do: foreach $acl (keys %data) { foreach $proto (keys %{$data{$acl}}) { foreach $port (sort { $data{$acl}{$proto}{$b} <=> $data{$acl}{$proto}{$a} } keys %{$data{$acl}{$proto}}) { # Do what you need } } } Otherwise, I'd just collapse the entire hash and sort: foreach $acl (keys %data) { foreach $proto (keys %{$data{$acl}}) { foreach $port (sort { $data{$acl}{$proto}{$b} <=> $data{$acl}{$proto}{$a} } keys %{$data{$acl}{$proto}}) { $new{"$acl:$proto:$port"} = $data{$acl}{$proto}{$port}; } } } foreach (sort { $new{$b} <=> $new{$a} } keys %new) { print "@{[ split(/:/, $_) ]} $new{$_}\n"; } I'm sure there's probably a better way, but brute-forcing it works. ;-) --Arthur Corliss Perl Monger/Alaska Perl Mongers http://www.alaskapm.org/ ================================================= Mailing list info: If at any time you wish to (un|re)subscribe to the list send the request to majordomo@hfb.pm.org. All requests should be in the body, and look like such subscribe anchorage-pm-list unsubscribe anchorage-pm-list From lsawyer at gci.com Tue Apr 17 16:38:05 2001 From: lsawyer at gci.com (Leif Sawyer) Date: Wed Aug 4 23:56:49 2004 Subject: Bizarre Question Message-ID: Aurthur replied: > On Tue, 17 Apr 2001, Leif Sawyer wrote: > > > What I'm trying to do, is print out a list of ports, by protocol, > > for each ACL. And i'd like the ports sorted by the number > > of packets, descending. > > To just sort it by acl, protocol, and packet count, in that > order, something > like this would do: > > foreach $acl (keys %data) { > foreach $proto (keys %{$data{$acl}}) { ###### this block is all i care about right now: > foreach $port (sort { $data{$acl}{$proto}{$b} <=> > $data{$acl}{$proto}{$a} } keys %{$data{$acl}{$proto}}) { > > # Do what you need ####### > > } > } > } > You'll find that this is what i tried, but it is not being sorted at all. It appears that there is some overriding of the variables within the sort routine, and it isn't getting the full values. ############### Attempt one ############ foreach $port (sort mostusedsvc keys %{$service{$acl}{$proto}}) { my($name,$aliases,$p,$t) = getservbyport($port,$proto); print "Port: $port ($name) = " , $service{$acl}{$proto}{$port} , "\n"; } sub mostusedsvc { $service{$acl}{$proto}{$b} <=> $service{$acl}{$proto}{$a} } :: This prints in seemingly random order. ############### Attempt two ############ @ports = sort { $service{$acl}{$proto}{$b} <=> $service{$acl}{$proto}{$b} } keys %{$service{$acl}{$proto}}; foreach $port ( @ports ) { my($n,$a,$p,$t) = getservbyport($port,$proto); print "Port: $port ($n) = " , $service{$acl}{$proto}{$port} , "\n"; } :: This also prints in seemingly random order These are both functionally the same, and should each behave as one expected, but for some reason, neither work. Where is the grammatical difference between my two versions, and your versions, that keep mine from working? ================================================= Mailing list info: If at any time you wish to (un|re)subscribe to the list send the request to majordomo@hfb.pm.org. All requests should be in the body, and look like such subscribe anchorage-pm-list unsubscribe anchorage-pm-list From michael at shoebox.net Tue Apr 17 16:50:53 2001 From: michael at shoebox.net (Michael Fowler) Date: Wed Aug 4 23:56:49 2004 Subject: Bizarre Question In-Reply-To: ; from lsawyer@gci.com on Tue, Apr 17, 2001 at 10:11:56AM -0800 References: Message-ID: <20010417135053.B1548@shoebox.net> On Tue, Apr 17, 2001 at 10:11:56AM -0800, Leif Sawyer wrote: > What I'm trying to do, is print out a list of ports, by protocol, > for each ACL. And i'd like the ports sorted by the number of packets, > descending. >From the code you showed us, I can't really see what you may have done wrong. Perhaps it's that I don't understand how you wanted this sorted. Anyhow, below my signature is the test code I used. Below this paragraph is the output it produces, indented to distinguish it. input-1 icmp 8 7000 tcp 110 4000 23 200 22 4 udp 53 7000000 31337 80000 input-2 icmp 10 4000 8 20 tcp 113 40 53 10 udp 53 700 Is this the sort order you were looking for? If not, you should take the example data and restructure it so that we have a better idea of what you're looking for. Michael -- Administrator www.shoebox.net Programmer, System Administrator www.gallanttech.com -- #!/usr/bin/perl -w use strict; # some seed data my %services = ( 'input-1' => { tcp => { 23 => 200, 110 => 4000, 22 => 4, }, udp => { 31337 => 80000, 53 => 7000000, }, icmp => { 8 => 7000, }, }, 'input-2' => { tcp => { 113 => 40, 53 => 10, }, udp => { 53 => 700, }, icmp => { 10 => 4000, 8 => 20, }, }, ); foreach my $acl (sort keys(%services)) { print "$acl\n"; foreach my $proto (sort keys(%{ $services{$acl} })) { print " $proto\n"; foreach my $port ( sort { $services{$acl}{$proto}{$b} <=> $services{$acl}{$proto}{$a} } keys(%{ $services{$acl}{$proto} }) ) { print " $port $services{$acl}{$proto}{$port}\n"; } print "\n"; } print "\n"; } ================================================= Mailing list info: If at any time you wish to (un|re)subscribe to the list send the request to majordomo@hfb.pm.org. All requests should be in the body, and look like such subscribe anchorage-pm-list unsubscribe anchorage-pm-list From michael at shoebox.net Tue Apr 17 17:07:11 2001 From: michael at shoebox.net (Michael Fowler) Date: Wed Aug 4 23:56:49 2004 Subject: Bizarre Question In-Reply-To: ; from lsawyer@gci.com on Tue, Apr 17, 2001 at 01:38:05PM -0800 References: Message-ID: <20010417140711.A1834@shoebox.net> On Tue, Apr 17, 2001 at 01:38:05PM -0800, Leif Sawyer wrote: > ############### Attempt two ############ > > @ports = sort { $service{$acl}{$proto}{$b} <=> $service{$acl}{$proto}{$b} } ^^ ^^ Is this a typo? If not, that would explain your apparent random sorting in this case. > keys %{$service{$acl}{$proto}}; Michael -- Administrator www.shoebox.net Programmer, System Administrator www.gallanttech.com -- ================================================= Mailing list info: If at any time you wish to (un|re)subscribe to the list send the request to majordomo@hfb.pm.org. All requests should be in the body, and look like such subscribe anchorage-pm-list unsubscribe anchorage-pm-list From lsawyer at gci.com Tue Apr 17 17:15:52 2001 From: lsawyer at gci.com (Leif Sawyer) Date: Wed Aug 4 23:56:49 2004 Subject: Bizarre Question Message-ID: Hmm... Here's a link to my perl script and data file. http://wormhole.anchorageak.net/pm/ there's a small 5000 line data file, and a rather large data file as well. both exhibit the same behavior. There some cruft in the script for future use.. :-) ================================================= Mailing list info: If at any time you wish to (un|re)subscribe to the list send the request to majordomo@hfb.pm.org. All requests should be in the body, and look like such subscribe anchorage-pm-list unsubscribe anchorage-pm-list