2

I just learned about ngrep, a cool program that lets you easily sniff packets that match a particular string.

The only problem is that it can be hard to see the match in the big blob of output. I'd like to write a wrapper script to highlight these matches -- it could use ANSI escape sequences:

echo -e 'This is \e[31mRED\e[0m.'

I'm most familiar with Perl, but I'm perfectly happy with a solution in Python or any other language. The simplest approach would be something like:

while (<STDIN>) {
   s/$keyword/\e[31m$keyword\e[0m/g;
   print;
}

However, this isn't a nice solution, because ngrep prints out hash marks without newlines whenever it receives a non-matching packet, and the code above will suppress the printing of these hashmarks until the script sees a newline.

Is there any way to do the highlighting without inhibiting the instant appearance of the hashmarks?

raldi
  • 21,344
  • 33
  • 76
  • 86

7 Answers7

4

This seems to do the trick, at least comparing two windows, one running a straight ngrep (e.g. ngrep whatever) and one being piped into the following program (with ngrep whatever | ngrephl target-string).

#! /usr/bin/perl

use strict;
use warnings;

$| = 1; # autoflush on

my $keyword = shift or die "No pattern specified\n";
my $cache   = '';

while (read STDIN, my $ch, 1) {
    if ($ch eq '#') {
        $cache =~ s/($keyword)/\e[31m$1\e[0m/g;
        syswrite STDOUT, "$cache$ch";
        $cache = '';
    }
    else {
        $cache .= $ch;
    }
}
dland
  • 4,319
  • 6
  • 36
  • 60
  • Nice answer! It's worth noting this will treat $keyword as a Perl regexp, which is good if that's what you want. If we want to treat it as a literal string, then (\Q$keyword\E) in the match will do that, as will my $keyword = quotemeta(shift) or die ... – pjf Oct 18 '08 at 14:54
3

Ah, forget it. This is too much of a pain. It was a lot easier to get the source to ngrep and make it print the hash marks to stderr:

--- ngrep.c     2006-11-28 05:38:43.000000000 -0800
+++ ngrep.c.new 2008-10-17 16:28:29.000000000 -0700
@@ -687,8 +687,7 @@
     }

     if (quiet < 1) {
-        printf("#");
-        fflush(stdout);
+      fprintf (stderr, "#");
     }

     switch (ip_proto) {                 

Then, filtering is a piece of cake:

while (<CMD>) {
  s/($keyword)/\e[93m$1\e[0m/g;
  print;
}
raldi
  • 21,344
  • 33
  • 76
  • 86
3

You could also pipe the output through ack. The --passthru flag will help.

Andy Lester
  • 91,102
  • 13
  • 100
  • 152
1

It shouldn't be too hard if you have the answer this question.

(Essentially, read one character at a time and if it's a hash, print it. If it isn't a hash, save the character to print out later.)

Community
  • 1
  • 1
Jon 'links in bio' Ericson
  • 20,880
  • 12
  • 98
  • 148
  • Well, yes -- I'm the one who asked that question! I'm trying to figure out what's the elegant way to do this -- should I be using nonblocking I/O? getc()? Do I really need to write my own readline() replacement? Sample code would be really helpful here. – raldi Oct 17 '08 at 23:15
1

why not just call ngrep with the -q parameter to eliminate the hash marks?

0

This is easy in python.

#!/usr/bin/env python
import sys, re

keyword = 'RED'

while 1:
    c = sys.stdin.read(1)
    if not c:
        break
    if c in '#\n':
        sys.stdout.write(c)
    else:
        sys.stdout.write(
            (c+sys.stdin.readline()).replace(
            keyword, '\x1b[31m%s\x1b[0m\r' % keyword))
Alex Coventry
  • 68,681
  • 4
  • 36
  • 40
-1

See the script at this post to Linux-IL where someone asked a similar question. It's written in Perl and uses the CPAN Term::ANSIColor module.

Shlomi Fish
  • 4,380
  • 3
  • 23
  • 27