I am trying to display only the data section of an udp packet using tcpdump. In some other words, is it any way to filter the header section of the udp package?

The below command

sudo tcpdump -Aq -i lo udp  port 1234 



How can I discard the E..".J@.@.U~.........v.....! part?


Here are a few ways. In the examples below I am using echo to print the specific string from your answer but you can replace the echo 'blah blah' | command with sudo tcpdump -Aq -i lo udp port 1234 | command.

  1. awk

    $ echo 'E..".J@.@.U~.........v.....!HELLO' | awk -F'!' '{print $NF}'

    awk splits the input lines into fields by splitting on the character given as -F. In this case, !. $NF is a special variable that means the last field. So, the command above, takes ! as the field separator and prints the last field, i.e. whatever comes after the last !.

  2. grep

    echo 'E..".J@.@.U~.........v.....!HELLO' | grep -oP '!\K.+?$'

    The -o flag causes grep to print only the matched portion of the line and -P activates Perl Compatible Regular Expressions which give us \K. The regex is looking for a ! and the shortest string possible (.+?, the ? makes it look for the shortest) up to the end of the line ($). The \K means : discard what was matched before the \K. The result is that the ! (which is before the \K) is discarded and only the HELLO is printed.

  3. cut

    echo 'E..".J@.@.U~.........v.....!HELLO' | cut -d'!' -f2

    cut is a utility that, well, cuts lines. In this case, I am setting the field delimiter to ! and printing the 2nd field, the HELLO.

  4. perl

     echo 'E..".J@.@.U~.........v.....!HELLO' | perl -pe 's/.+\!//'

    The -p means "print every line after applying the script given with -e to it". The script itself uses the substitution operator (s/pattern/replacement/) to replace everything up to the last ! (here, since there is no ?, the .+ will match the longest possible string) with nothing, effectively leaving only the HELLO.


Try this,

$ echo 'E..".J@.@.U~.........v.....!HELLO' | grep -oP '!+.*' | sed 's/.\(.*\)/\1/g'
  • 2
    this also will work echo 'E..".J@.@.U~.........v.....!HELLO' | sed 's/.*\!//' Apr 16 '14 at 15:01

Based on the structure of the udp packet, you should cut the tcpdump output from a specific location, instead of looking for a certain character, which could also change:

sudo tcpdump -Aq -i lo udp  port 1234 | cut -c29-

For example, sending a udp packet with netcat:

echo "HELLO" | netcat -4u -w1 localhost 1234

this is my tcpdump output (in hex and ascii ):

sudo tcpdump -X -i lo udp port 1234

12:35:10.672236 IP localhost.36898 > localhost.1234: UDP, length 6
     0x0000:  4500 0022 ab0e 4000 4011 91ba 7f00 0001  E.."..@.@.......
     0x0010:  7f00 0001 9022 04d2 000e fe21 4845 4c4c  .....".....!HELL
     0x0020:  4f0a                                     O.

but, sending another string, like:

echo "HELLOS" | netcat -4u -w1 localhost 1234

this is the output:

12:50:01.987211 IP localhost.45180 > localhost.1234: UDP, length 7
    0x0000:  4500 0023 3873 4000 4011 0455 7f00 0001  E..#8s@.@..U....
    0x0010:  7f00 0001 b07c 04d2 000f fe22 4845 4c4c  .....|....."HELL
    0x0020:  4f53 0a                                  OS.

the character before the string "HELLOS" is changed, because the 2 byte preceding the date section are related to the udp checksum, and then change according to the packet sent.

whireshark screenshot:


enter image description here

UDP packet:

UDP and 2 byte checksum:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.