wireshark/tools/checkfiltername.pl
Michael Mann 65379209d6 Add support for (ignoring) idl2wrs generated dissectors.
Add commandline options to show file line numbers of dissectors.  The default is to have no line numbers shown as its easier to compare results without a minor file change causing the line number of the filter to change resulting in an unnecessary difference.
Add commandline option to check filter names of automated files (default disabled).
Check for underscores prefacing or following a period in filter names as this is probably a typo.
Cleaned up output when checking a single file.

svn path=/trunk/; revision=44182
2012-08-01 03:10:34 +00:00

516 lines
14 KiB
Perl
Executable file

#!/usr/bin/perl
my $debug = 0;
# 0: off
# 1: specific debug
# 2: full debug
#
# verify that display filter names correspond with the PROTABBREV of
# of the dissector. Enforces the dissector to have a source
# filename of format packet-PROTABBREV.c
#
# Usage: checkfiltername.pl <file or files>
# $Id$
#
# Copyright 2011 Michael Mann (see AUTHORS file)
#
# Wireshark - Network traffic analyzer
# By Gerald Combs <gerald@wireshark.org>
# Copyright 1998 Gerald Combs
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Example:
# ~/work/wireshark/trunk/epan/dissectors> ../../tools/checkfiltername.pl packet-3com-xns.c
# packet-3com-xns.c (2 (of 2) fields)
# 102 3comxns.type doesn't match PROTOABBREV of 3com-xns
# 106 3comxns.type doesn't match PROTOABBREV of 3com-xns
#
# or checkfiltername.pl packet-*.c, which will check all the dissector files.
#
#
use warnings;
use strict;
use Getopt::Long;
my @elements;
my @elements_dup;
my @protocols;
my %filters;
my @acceptedprefixes = ("dcerpc-");
my @asn1automatedfilelist;
my @dcerpcautomatedfilelist;
my @idl2wrsautomatedfilelist;
my @filemanipulationfilelist;
my @prefixfilelist;
my @nofieldfilelist;
my %unique;
my @uniquefilelist;
my @noregprotocolfilelist;
my $showlinenoFlag = '';
my $showautomatedFlag = '';
my $state;
# "s_unknown",
# "s_start",
# "s_in_hf_register_info",
# "s_hf_register_info_entry",
# "s_header_field_info_entry",
# "s_header_field_info_entry_start",
# "s_header_field_info_entry_name",
# "s_header_field_info_entry_abbrev",
# "s_header_field_info_entry_abbrev_end",
# "s_nofields"
my $restofline;
my $filecount = 0;
my $currfile = "";
my $protabbrev = "";
my $protabbrev_index;
my $linenumber = 1;
my $totalerrorcount = 0;
my $errorfilecount = 0;
my $onefield = 0;
my $nofields = 0;
my $noregprotocol = 1;
my $automated = 0;
my $more_tokens;
my $showall = 0;
my $comment = 0;
my $error = 0;
sub checkprotoabbrev {
my $abbrev = "";
my $abbrevpos;
my $afterabbrev = "";
my $modprotabbrev = "";
my $errorline = 0;
my $prefix;
if (($automated == 0) || ($showall == 1)) {
$abbrevpos = index($_[0], ".");
if ($abbrevpos == -1) {
$abbrev = $_[0];
}
else {
$abbrev = substr($_[0], 0, $abbrevpos);
$afterabbrev = substr($_[0], $abbrevpos+1, length($_[0])-$abbrevpos);
$afterabbrev = substr($afterabbrev, 0, length($abbrev));
}
if ($abbrev ne $protabbrev) {
$errorline = 1;
#check if there is a supported protocol that matches the abbrev.
#This may be a case of filename != PROTOABBREV
foreach (@protocols) {
if ($abbrev eq $_) {
$errorline = 0;
}
}
}
# find any underscores that preface or follow a period
if ((index($_[0], "._") >= 0) || (index($_[0], "_.") >= 0)) {
if ($showlinenoFlag) {
push(@elements, "$_[1] $_[0] contains an unnecessary \'_\'\n");
} else {
push(@elements, "$_[0] contains an unnecessary \'_\'\n");
}
}
if (($errorline == 1) && ($showall == 0)) {
#try some "accepted" variations of PROTOABBREV
#replace '-' with '_'
$modprotabbrev = $protabbrev;
$modprotabbrev =~ s/-/_/g;
if ($abbrev eq $modprotabbrev) {
$errorline = 0;
}
#remove '-'
if ($errorline == 1) {
$modprotabbrev = $protabbrev;
$modprotabbrev =~ s/-//g;
if ($abbrev eq $modprotabbrev) {
$errorline = 0;
}
}
#remove '_'
if ($errorline == 1) {
$modprotabbrev = $protabbrev;
$modprotabbrev =~ s/_//g;
if ($abbrev eq $modprotabbrev) {
$errorline = 0;
}
}
if ($errorline == 1) {
#remove any "accepted" prefix to see if there is still a problem
foreach (@acceptedprefixes) {
if ($protabbrev =~ /^$_/) {
$modprotabbrev = substr($protabbrev, length($_));
if ($abbrev eq $modprotabbrev) {
push(@prefixfilelist, "$currfile\n");
$errorline = 0;
}
}
}
} else {
push(@filemanipulationfilelist, "$currfile\n");
}
}
if ($errorline == 1) {
$debug>1 && print "$_[1] $_[0] doesn't match PROTOABBREV of $protabbrev\n";
if ($showlinenoFlag) {
push(@elements, "$_[1] $_[0] doesn't match PROTOABBREV of $protabbrev\n");
} else {
push(@elements, "$_[0] doesn't match PROTOABBREV of $protabbrev\n");
}
}
if (lc($abbrev) eq lc($afterabbrev)) {
if ($showlinenoFlag) {
push(@elements_dup, "$_[1] $_[0] duplicates PROTOABBREV of $abbrev\n");
} else {
push(@elements_dup, "$_[0] duplicates PROTOABBREV of $abbrev\n");
}
}
}
}
sub printprevfile {
my $totalfields = keys(%filters);
my $count_ele;
my $count_dup;
my $total_count;
foreach (sort keys %filters) {
checkprotoabbrev ($filters{$_}, $_);
}
$count_ele = @elements;
$count_dup = @elements_dup;
$total_count = $count_ele+$count_dup;
if ($noregprotocol == 1) {
#if no protocol is registered, only worry about duplicates
if ($currfile ne "") {
push(@noregprotocolfilelist, "$currfile\n");
}
if ($count_dup > 0) {
$errorfilecount++;
$totalerrorcount += $count_dup;
}
if (($showall == 1) || ($count_dup > 0)) {
print "\n\n$currfile - NO PROTOCOL REGISTERED\n";
if ($showall == 1) {
#everything is included, so count all errors
$totalerrorcount += $count_ele;
if (($count_ele > 0) && ($count_dup == 0)) {
$errorfilecount++;
}
foreach (@elements) {
print $_;
}
}
foreach (@elements_dup) {
print $_;
}
}
} else {
if ($total_count > 0) {
$errorfilecount++;
$totalerrorcount += $total_count;
}
if (($automated == 0) || ($showall == 1)) {
if ($total_count > 0) {
if ($automated == 1) {
if ($showall == 1) {
print "\n\n$currfile - AUTOMATED ($total_count (of $totalfields) fields)\n";
}
} else {
print "\n\n$currfile ($total_count (of $totalfields) fields)\n";
}
foreach (@elements) {
print $_;
}
foreach (@elements_dup) {
print $_;
}
}
if ((($nofields) || ($totalfields == 0)) && ($currfile ne "")) {
if ($showall == 1) {
print "\n\n$currfile - NO FIELDS\n";
}
push(@nofieldfilelist, "$currfile\n");
}
}
}
}
# ---------------------------------------------------------------------
#
# MAIN
#
GetOptions(
'showlineno' => \$showlinenoFlag,
'showautomated' => \$showautomatedFlag,
);
while (<>) {
if ($currfile !~ /$ARGV/) {
&printprevfile();
# New file - reset array and state
$filecount++;
$currfile = $ARGV;
#determine PROTABBREV for dissector based on file name format of (dirs)/packet-PROTABBREV.c
$protabbrev_index = rindex($currfile, "packet-");
if ($protabbrev_index == -1) {
print "$currfile doesn't fit format of packet-PROTABBREV.c\n";
next;
}
$protabbrev = substr($currfile, $protabbrev_index+length("packet-"));
$protabbrev_index = rindex($protabbrev, ".");
if ($protabbrev_index == -1) {
print "$currfile doesn't fit format of packet-PROTABBREV.c\n";
next;
}
$protabbrev = substr($protabbrev, 0, $protabbrev_index);
$noregprotocol = 1;
$automated = 0;
$nofields = 0;
$onefield = 0;
$linenumber = 1;
%filters = ( );
@protocols = ( );
@elements = ( );
@elements_dup = ( );
$state = "s_unknown";
}
if (($automated == 0) && ($showautomatedFlag eq "")) {
#DCERPC automated files
if ($_ =~ "DO NOT EDIT") {
push(@dcerpcautomatedfilelist, "$currfile\n");
$automated = 1;
next;
}
#ASN.1 automated files
elsif ($_ =~ "It is created automatically by the ASN.1 to Wireshark dissector compiler") {
push(@asn1automatedfilelist, "$currfile\n");
$automated = 1;
next;
}
#idl2wrs automated files
elsif ($_ =~ "Autogenerated from idl2wrs") {
push(@idl2wrsautomatedfilelist, "$currfile\n");
$automated = 1;
next;
}
}
# opening then closing comment
if (/(.*?)\/\*.*\*\/(.*)/) {
$comment = 0;
$_ = "$1$2";
# closing then opening comment
} elsif (/.*?\*\/(.*?)\/\*/) {
$comment = 1;
$_ = "$1";
# opening comment
} elsif (/(.*?)\/\*/) {
$comment = 1;
$_ = "$1";
# closing comment
} elsif (/\*\/(.*?)/) {
$comment = 0;
$_ = "$1";
} elsif ($comment == 1) {
$linenumber++;
next;
}
# unhandled: more than one complete comment per line
chomp;
#proto_register_protocol state machine
$restofline = $_;
$more_tokens = 1;
until ($more_tokens == 0) {
if ($restofline =~ /proto_register_protocol\s*\((.*)/) {
$noregprotocol = 0;
$restofline = $1;
$state = "s_proto_start";
} elsif (($state eq "s_proto_start") && ($restofline =~ /^(\s*\"([^\"]*)\"\s*,)\s*(.*)/)) {
$restofline = $3;
$state = "s_proto_long_name";
$debug>1 && print "proto long name: '$2'\n";
} elsif (($state eq "s_proto_start") && ($restofline =~ /^(\s*(([\w\d])+)\s*,)\s*(.*)/)) {
$restofline = $4;
$state = "s_proto_long_name";
$debug>1 && print "proto long name: '$2'\n";
} elsif (($state eq "s_proto_long_name") && ($restofline =~ /^(\s*\"([^\"]*)\"\s*,)\s*(.*)/)) {
$restofline = $3;
$state = "s_proto_short_name";
$debug>1 && print "proto short name: '$2'\n";
} elsif (($state eq "s_proto_long_name") && ($restofline =~ /^(\s*(([\w\d])+)\s*,)\s*(.*)/)) {
$restofline = $4;
$state = "s_proto_short_name";
$debug>1 && print "proto short name: '$2'\n";
} elsif (($state eq "s_proto_short_name") && ($restofline =~ /\s*\"([^\"]*)\"\s*(.*)/)) {
$more_tokens = 0;
$state = "s_proto_filter_name";
push(@protocols, $1);
$debug>1 && print "proto filter name: '$1'\n";
} elsif (($state eq "s_proto_short_name") && ($restofline =~ /\s*(([\w\d])+)\s*(.*)/)) {
$more_tokens = 0;
$state = "s_proto_filter_name";
$debug>1 && print "proto filter name: '$1'\n";
} else {
$more_tokens = 0;
}
}
#retrieving display filters state machine
$restofline = $_;
$more_tokens = 1;
until ($more_tokens == 0) {
if ($restofline =~ /\s*static\s*hf_register_info\s*(\w+)\[\](.*)/) {
$restofline = $2;
$state = "s_start";
$debug>1 && print "$linenumber $state\n";
} elsif (($state eq "s_start") && ($restofline =~ /\W+{(.*)/)) {
$restofline = $1;
$state = "s_in_hf_register_info";
$debug>1 && print "$linenumber $state\n";
} elsif (($state eq "s_in_hf_register_info") && ($restofline =~ /\W+{(.*)/)) {
$restofline = $1;
$state = "s_hf_register_info_entry";
$debug>1 && print "$linenumber $state\n";
$onefield = 1;
} elsif (($state eq "s_in_hf_register_info") && ($restofline =~ /\s*};(.*)/)) {
$restofline = $1;
if ($onefield == 0) {
$debug && print "$linenumber NO FIELDS!!!\n";
$nofields = 1;
$state = "s_nofields";
$more_tokens = 0;
} else {
$state = "s_unknown";
}
} elsif (($state eq "s_hf_register_info_entry") && ($restofline =~ /\s*&\s*(hf_\w*(\[w*\])?)\s*,?(.*)/)) {
$restofline = $3;
$debug>1 && print "$linenumber hf_register_info_entry: $1\n";
$state = "s_header_field_info_entry";
} elsif (($state eq "s_header_field_info_entry") && ($restofline =~ /\s*{(.*)/)) {
$restofline = $1;
$state = "s_header_field_info_entry_start";
$debug>1 && print "$linenumber $state\n";
} elsif (($state eq "s_header_field_info_entry_start") && ($restofline =~ /\"([^\"]*)\"\s*,(.*)/)) {
$restofline = $2;
$debug>1 && print "$linenumber header_field_info_entry_name: $1\n";
$state = "s_header_field_info_entry_name";
} elsif (($state eq "s_header_field_info_entry_name") && ($restofline =~ /\"([^\"]*)\"\s*,?(.*)/)) {
$restofline = $2;
$debug>1 && print "$linenumber header_field_info_entry_abbrev: $1\n";
$state = "s_header_field_info_entry_abbrev";
$filters{$linenumber} = $1;
} elsif (($state eq "s_header_field_info_entry_abbrev") && ($restofline =~ /[^}]*}(.*)/)) {
$restofline = $1;
$state = "s_header_field_info_entry_abbrev_end";
$debug>1 && print "$linenumber $state\n";
} elsif (($state eq "s_header_field_info_entry_abbrev_end") && ($restofline =~ /[^}]*}(.*)/)) {
$restofline = $1;
$state = "s_in_hf_register_info";
$debug>1 && print "$linenumber $state\n";
} else {
$more_tokens = 0;
}
}
$linenumber++;
}
&printprevfile();
print "\n\nTOTAL ERRORS: $totalerrorcount";
if ($filecount > 1) {
print " ($errorfilecount files)\n";
print "NO FIELDS: " . scalar(@nofieldfilelist) . "\n";
print "AUTOMATED: " . (scalar(@asn1automatedfilelist) + scalar(@dcerpcautomatedfilelist) + scalar(@idl2wrsautomatedfilelist)) . "\n";
print "NO PROTOCOL: " . scalar(@noregprotocolfilelist) . "\n";
print "\nASN.1 AUTOMATED FILE LIST\n";
foreach (@asn1automatedfilelist) {
print $_;
}
print "\nDCE/RPC AUTOMATED FILE LIST\n";
foreach (@dcerpcautomatedfilelist) {
print $_;
}
print "\nIDL2WRS AUTOMATED FILE LIST\n";
foreach (@idl2wrsautomatedfilelist) {
print $_;
}
print "\n\"FILE MANIPULATION\" FILE LIST\n";
@uniquefilelist = grep{ not $unique{$_}++} @filemanipulationfilelist;
foreach (@uniquefilelist) {
print $_;
}
print "\nREMOVE PREFIX FILE LIST\n";
@uniquefilelist = grep{ not $unique{$_}++} @prefixfilelist;
foreach (@uniquefilelist) {
print $_;
}
print "\nNO PROTOCOL REGISTERED FILE LIST\n";
foreach (@noregprotocolfilelist) {
print $_;
}
print "\nNO FIELDS FILE LIST\n";
foreach (@nofieldfilelist) {
print $_;
}
}
print "\n";
exit $error;
__END__