Compare requests with tcpdump

As my introduction to tcpdump was only a theoretical one, today I have a real world example for you. Previously I faced the problem that a third party API call I made from host A via cURL PHP failed on a host B. Each time host A called the API it got back an error from host B that the request body of the HTTP request was malformed.

How to solve the problem

Anyway, when I made the same request with curl directly from the command line everything was fine.

make insecure ssl request with curl
Figure 1 – Make “insecure” SSL request with curl from command line with response indicating success.

Great! Now I had a command line request (that succeeded) that should theoretical be the same as the one I made with cURL in PHP (that failed). Normally I would now have captured the requests made from host A to host B but I had a SSL problem as you can see in figure 1. However, performing both requests to the loopback interface over HTTP to analyse and compare them did the job as well.

Now the goal was to compare the curl request from command line (that succeeded) and the one made with cURL PHP (that failed).

Write tcpdump capture to a file

Instead of write the packet information to stdout, tcpdump can write the raw packet information captured to a file as well.

Write captured loopback to file with tcpdump
Figure 2 – Write captured loopback network traffic to file with tcpdump.

While the capture of figure 2 was in progress, I performed the request mentioned in figure 1 against my loopback interface – this time over HTTP to overcome the SSL issue while capturing.

Analyse the tcpdump capture with Wireshark

Afterwards I transmitted curl-command-line.pcap with SFTP to my local desktop environment and opened it with the “Open a previous captured file” functionality in Wireshark.

Analyse a post request with Wireshark.
Figure 3 – Analyse the POST request made on the loopback interface – request details see figure 1.

If you compare the request details of figure 1 and figure 3 you can see that everything is present as expected.

So far  we have focused on retrieving the transmitted packet information for the curl request performed from command line (that succeeded). Now I did the same things described already for the cURL PHP request as well (that failed). By doing so, I was in the end able to find out about the differences of both requests by comparing them in Wireshark and fixed the cURL PHP request accordingly.

Problem solution in my specific case

The issue in my specific case was this code snippet:

curl_setopt($curl, CURLOPT_HEADER,
        array(
           'Content-Type: application/json',
           'Content-Length: '.strlen($body_str)
        )
);

Can you find the mistake?

Click me to display the solution:) CURLOPT_HEADER in the above code snippet is incorrect. As it was incorrect, the Content-Type of the request was automatically set to “application/x-www-form-urlencoded” by cURL PHP. The correct option to be set is CURLOPT_HTTPHEADER. By doing so the correct content type “application/json” will be set.