2
votes

I am interested in getting a count of all LDAP/Kerberos/DNS packets.

I tried the following, but this captures the full packet.

tcpdump -i any -Z root "tcp port 389 or tcp port 88 or udp port 53" -w ~/ldap_kerberos_dns.cap

Is there a way I can just capture how many ldap/Kerberos/DNS packets were exchanged
without actually capturing the full packet.

Expected output should be something like:

LDAP:     100  
Kerberos: 200  
UDP:      300  
2

2 Answers

3
votes

Take a look at tshark statistics:

$ tshark -r 04.pcap -q -z io,phs
===================================================================
Protocol Hierarchy Statistics
Filter:

eth                                      frames:649 bytes:124780
  ipv6                                   frames:605 bytes:116558
    udp                                  frames:212 bytes:33686
      dhcpv6                             frames:171 bytes:28044
      dns                                frames:25 bytes:2914
      ntp                                frames:10 bytes:1300
      cldap                              frames:6 bytes:1428
    icmpv6                               frames:80 bytes:7008
    tcp                                  frames:313 bytes:75864
      nbss                               frames:108 bytes:24063
        smb                              frames:7 bytes:1554
        smb2                             frames:101 bytes:22509
          tcp.segments                   frames:1 bytes:103
      dcerpc                             frames:16 bytes:4264
        epm                              frames:2 bytes:544
        tcp.segments                     frames:1 bytes:214
        drsuapi                          frames:8 bytes:2352
      kerberos                           frames:16 bytes:9358
        tcp.segments                     frames:8 bytes:2130
      dcerpc.cn_deseg_req                frames:1 bytes:1514
      ldap                               frames:16 bytes:5945
        tcp.segments                     frames:3 bytes:1101
          ldap                           frames:1 bytes:803
  ip                                     frames:40 bytes:8018
    udp                                  frames:40 bytes:8018
      nbdgm                              frames:30 bytes:7300
        smb                              frames:30 bytes:7300
          mailslot                       frames:30 bytes:7300
            browser                      frames:30 bytes:7300
      dns                                frames:10 bytes:718
  arp                                    frames:4 bytes:204
===================================================================

See the man-page for more information.

3
votes

tshark approach

If you have Wireshark (based on question tags, not the actual question) then tshark along the lines of @joke's comment is one way to go, if you don't mind its verbose stats output:

tshark -i any -n -q -z 'io,stat,0,FRAMES()tcp.port==389,FRAMES()tcp.port==88,FRAMES()udp.port==53'
Capturing on Pseudo-device that captures on all interfaces
^C142 packets captured

=============================================
| IO Statistics                             |
|                                           |
| Interval size: 4.319 secs (dur)           |
| Col 1: FRAMES()tcp.port==389              |
|     2: FRAMES()tcp.port==88               |
|     3: FRAMES()udp.port==53               |
|-------------------------------------------|
|                |1       |2       |3       |
| Interval
| Interval       | FRAMES | FRAMES | FRAMES |
|-------------------------------------------|
| 0.000 <> 4.319 |    100 |    200 |    300 |
=============================================

Though the output from that is verbose, I don't think you can get closer with tshark alone. Another approach, still more verbose, would be:

tshark -q -z io,phs "tcp port 389 or tcp port 88 or udp port 53"

These two commands do not write a capture file. Use Ctrl+C when you're ready to quit, or see the comment below about -a and autostop conditions. One caveat is that those statistics rely on the protocol dissectors, not the source/destination ports, so there can be discrepancies (e.g. connections with no data, or content non-compliant with protocol), "malformed" packets will be reported instead. It also means you won't get reliable results if you optimize and only capture 40 bytes per packet ("short" TCP or UDP packets will be reported instead).

tcpdump approach

A simple, but inelegant way is to run multiple tcpdump instances (assume bash as a shell) --

for pp in "tcp port 88" "tcp port 389" "udp port 53"; do
    tcpdump -i any -Z root $pp -w /dev/null  2> ${pp// /-}.stats &
done

Packets are not written to a capture file (discarded via /dev/null). Then wait as required, kill the tcpdump processes (by PID as listed, or kill %1 %2 %3 if no other background jobs), and inspect the .stats files:

grep captured *.stats
tcp-port-389.stats:0 packets captured
tcp-port-88.stats:0 packets captured
udp-port-53.stats:4 packets captured

perl approach

Since this is stackoverflow, here's a quick and dirty perl/libpcap solution (just add error handling):

#!/usr/bin/perl

use Net::Pcap;
use NetPacket::Ethernet;
use NetPacket::IP;
use NetPacket::TCP;
use strict;
use warnings;

my ($dev,$err,$address, $netmask,$pcap,$filter,$cfilter,$fd,%stats);
my $bail=0;
my ($rin,$rout)=('','');

$SIG{INT} = sub { print "quit...\n"; $bail=1; };

$filter='(tcp port 88 or tcp port 389 or udp port 53)';

$dev=Net::Pcap::lookupdev(\$err);
Net::Pcap::lookupnet($dev, \$address, \$netmask, \$err);
$pcap = Net::Pcap::open_live($dev, 60, 1, 0, \$err);
Net::Pcap::pcap_setnonblock($pcap, 1, \$err);
$fd=Net::Pcap::pcap_get_selectable_fd($pcap);
vec($rin,$fd,1)=1;

Net::Pcap::compile( $pcap, \$cfilter, $filter, 0, $netmask);
Net::Pcap::setfilter($pcap, $cfilter);

while (Net::Pcap::dispatch($pcap,0, \&handlepackets, '')>=0) { 
    select($rout=$rin,undef,undef,0.250);
    printf("."); $|=1;
    $bail && last;
};
Net::Pcap::freecode($cfilter);
Net::Pcap::close($pcap);

sub handlepackets() {
    my ($user_data, $header, $packet) = @_;

    my $ether = NetPacket::Ethernet::strip($packet);
    my $ip    = NetPacket::IP->decode($ether);
    my $tcp   = NetPacket::TCP->decode($ip->{'data'});

    if      ($tcp->{'src_port'} < 1024)  {
        $stats{$tcp->{'src_port'}}++;
    } elsif ($tcp->{'dest_port'} < 1024) {
        $stats{$tcp->{'dest_port'}}++;
    }
}

END {
    if (keys %stats) {
        for my $kk (sort keys %stats) {
            my ($name, $aliases, $port, $prot)=getservbyport($kk,"tcp");
            printf("%12s %4i\n",$name,$stats{$kk});
        }
    } else { printf("No stats...\n"); } 
}