No cabeçalho IP, você tem um cabeçalho TOTAL COMPRIMENTO que contém "o comprimento do datagrama, medido em octetos, incluindo o cabeçalho e os dados da Internet". (RFC 791). Se você deseja ter apenas o tamanho de carga útil de um pacote, você precisa fazer TOTAL LENGTH menos (comprimento do cabeçalho IP + (TCP | UDP) comprimento do cabeçalho). (O comprimento do cabeçalho IP está no cabeçalho do DIH, o comprimento do cabeçalho TCP está no cabeçalho do deslocamento de dados).
Com um comando tcpdump básico, como
# tcpdump -s 1500 -Svni eth0 tcp and port 80
Eu mostrarei cada pacote TCP como segue
11:58:52.114411 IP (tos 0x0, ttl 53,id 5745, offset 0, flags [DF], proto TCP (6), length 505)
12.66.33.88.53247 > 88.231.98.32.80: Flags [P.], cksum 0x62fd (correct), seq 1193308573:1193309026, ack 2122411067, win 46, options [nop,nop,TS val 122841090 ecr 125780554], length 453
A primeira linha contém o cabeçalho IP, incluindo o comprimento total (comprimento 505). A segunda linha contém o cabeçalho tcp, incluindo o comprimento da carga útil (comprimento 453), que é 505 - 52 (sendo 52 o comprimento dos cabeçalhos IP + TCP).
Se você quiser automatizar isso, você pode definir o tcpdump para armazenar a captura em um arquivo pcap e, em seguida, analisar o pcap com um script.
No entanto, se você quiser fazer isso rapidamente, sem degradar suas performances, você deve dar uma olhada em libnetfilter_queue. Isso envolve um pouco de codificação em C, mas não muito. A idéia é que você coloque um gancho no netfilter para direcionar o tráfego para o seu programa. A partir daí, você pode analisar os cabeçalhos ip | tcp | udp e calcular suas informações, colocar isso em um banco de dados RRD, se desejar, e reinjetar o tráfego no netfilter.