Search code examples
tcpdumpngrep

ngrep - inverted port results


I'm curious if ngrep can do inverted matched based on ports? I've tried something along the lines of:

ngrep -d any -v port 22
interface: any
filter: ( port 22 ) and (ip or ip6)

And although it says the filter is for 'port 22', it doesn't pick up any of the ports. Tried googling this for a couple of days, and haven't found a solution. Can anyone who is familiar with ngrep let me know if this is doable?


Solution

  • Wow. ngrep's command-line syntax really is a greasy hack.

    The ngrep man page says:

    ngrep {various flags} <match expression> <bpf filter>
    

    without indicating how ngrep manages to tell what's part of the "match expression" and what's part of the "bpf filter".

    The way it determines that is by:

    • taking the first shell token after the flag arguments, if present, as the "match expression" and, if there are any tokens after it, gluing them all together with spaces between them and making that the "bpf filter";
    • if it finds a "bpf filter", trying to compile it and:
    • if that succeeds, using what it found as the "match expression" and the "bpf filter";
    • if that fails, assuming there was no "match expression", taking all the tokens after the flag arguments, gluing them together to make the "bpf filter".

    This means that if you do ngrep port 22, it first tries to use "port" as the "match expression" and "22" as the "bpf filter", which fails because "22" isn't a valid BPF filter, and then assumes that there isn't a "match expression" and that "port 22" is the "bpf filter", which works.

    However, if you do ngrep not port 22, it first tries to use "not" as the "match expression" and "port 22" as the "bpf filter", which succeeds, so you end up with "not" as the filter with which it tries grepping and "port 22" as the BPF filter it hands to libpcap.

    Sadly, ngrep has no way of saying "there's no match expression, there's just a BPF filter", so you have to do something such as ngrep "" not port 22, with an empty match expression to have it recognize "not port 22" as the BPF filter.

    So, if you want to see all traffic except for traffic to port 22, try

    ngrep -d any "" not port 22
    

    -v affects the match expression, NOT the BPF filter; that means that the command you gave in your question will match only packets to or from port 22, not packets not to or from port 22. As you want the empty match expression to match all packets, rather than no packets, you would leave the -v flag out.