Linux – How to capture contents of the first packet of TCP connections using tcpdump

linuxnetworkingpcaptcpdump

I'm tasked with monitoring and debugging a SOAP web service, on network level. I can use tcpdump to capture the whole traffic coming from customers on port 80, but I can't limit the capture for every request to just the first received application-layer packet (the most significant packet in this case, which carries the HTTP request header and beginning of SOAP XML document). I want to know which tcpdump switch (or combination of other linux commands) to use to get this first packet for each TCP connection, and drop the rest of packets received for the same connection.

If possible, having the first response packet (and probably the only, because in this application, response XML documents are small) sent from server to customer, would be nice too.

Currently I run tcpdump -i any -A 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' example from tcpdump man page, so I don't get the TCP handshake packets.

And the problem with -c switch is tcpdump exits after capturing the packet, while I need it to stay running and continue showing the same information for new connections. Ideally I need something similar to tailing apache access log files, along with first meaningful chunks of request and response.

Best Answer

So your request is actually narrower than the title suggests - you're specifically looking for HTTP requests.

I use ngrep for this, which combines tcpdump and grep type functionality. eg:

sudo ngrep -d eth0 '^(GET|POST) ' port 80

That will give you text output. If you want, you can use the -w option to write the matched packets to a file in tcpdump format.

Use -d as above to specify the interface, since -i is used as in grep for case insensitivity.

The above will also include outgoing requests and so forth that you might not want. append tcpdump type options as required.

If you're debugging requests to a particular URL, you might want to use that to make the regular expression more specific. eg

sudo ngrep '^(GET|POST) /my/soap/interface .*Host: myhost.example.com' 'dst port 80 and dst host myhost.example.com'

In the unusual case that the request is split over multiple packets with the Host header in the second packet, the above may fail to catch some requests. Mostly that doesn't matter, but you could always capture more than you need with tcpdump, break it into files with chaosreader, and then start grepping the files.